---
title: Tool reference
description: Every tool the GPS connector serves, grouped by area, with its inputs, who sees it and what it does.
product: gps
section: mcp
order: 5
---

# Tool reference

The GPS connector serves **110 tools**: 53 that read, 6 that preview a batch before it's applied, and 51 that make changes. Each one is listed below, grouped by area, with an anchor you can link to (for example `tools.md#tool-get-plan-scorecard`).

This page is built from the connector's own tool registry, so the names, inputs, limits and defaults are exactly what the connector serves. The descriptions are the ones your assistant reads, edited for US spelling.

Every tool acts as the person who connected it: it sees only what they can see in GPS, and does only what their role lets them do there. How calls, results, paging and refusals work is in [How it works](how-it-works.md). What changed, and when, is in the [changelog](changelog.md).

## Reading this reference

- **read** tools change nothing. **preview** tools change nothing either: they check a batch and return a token that their paired write tool applies. **write** tools change GPS.
- **Adds, never replaces:** the tool adds something new. Claude and ChatGPT treat it as a non-destructive change.
- **Can't be undone by the assistant:** the tool replaces something that's there, so Claude and ChatGPT ask you before running it. Many of these changes can still be undone by a person in GPS. See [Safety and privacy](safety.md#undo).
- **History keeps the old value:** the objective's History tab in GPS keeps the value the check-in replaced.
- **Emails people:** the tool sends an email or a calendar invite to people in GPS.
- **Reads a connected account live:** the tool reads an account the organization connected to GPS (for example Xero or HubSpot) as it runs, and may renew that account's sign-in. Nothing in GPS changes.
- **Who sees it:** a tool is only listed to connections that could use it. *Write connections only* means a View only connection never sees it. *myPortal consultants only* means it's listed only to consultants who run client accounts in myPortal.
- **Widget contract:** the versioned shape of the result, which the in-chat views and other readers rely on. See [Prompts, resources and widgets](prompts-resources-widgets.md).
- An input's limits follow its description in parentheses: a length, a range, a number of items, or its default.

| Who sees it | Tools |
|---|---|
| Everyone | 34 |
| Write connections only | 36 |
| myPortal consultants only | 19 |
| myPortal consultants, write connections only | 21 |

## Contents

- [Account](#account): [`get_my_profile`](#tool-get-my-profile), [`list_organizations`](#tool-list-organizations)
- [Plan: goals and objectives](#plan-goals-and-objectives): [`get_plan_scorecard`](#tool-get-plan-scorecard), [`list_goals`](#tool-list-goals), [`get_goal`](#tool-get-goal), [`list_objectives`](#tool-list-objectives), [`get_objective`](#tool-get-objective), [`create_goal`](#tool-create-goal), [`update_goal`](#tool-update-goal), [`create_objective`](#tool-create-objective), [`update_objective`](#tool-update-objective)
- [Next 90 days and progress](#next-90-days-and-progress): [`get_next_90_days`](#tool-get-next-90-days), [`get_objective_progress`](#tool-get-objective-progress), [`list_measurement_types`](#tool-list-measurement-types), [`record_objective_progress`](#tool-record-objective-progress), [`preview_progress_batch`](#tool-preview-progress-batch), [`record_progress_batch`](#tool-record-progress-batch)
- [Keeping a KPI in sync](#keeping-a-kpi-in-sync): [`list_sync_options`](#tool-list-sync-options), [`preview_objective_sync`](#tool-preview-objective-sync), [`set_objective_sync`](#tool-set-objective-sync), [`stop_objective_sync`](#tool-stop-objective-sync)
- [Actions](#actions): [`list_actions`](#tool-list-actions), [`get_action`](#tool-get-action), [`create_action`](#tool-create-action), [`preview_actions_batch`](#tool-preview-actions-batch), [`create_actions_batch`](#tool-create-actions-batch), [`update_action`](#tool-update-action)
- [Comments](#comments): [`list_comments`](#tool-list-comments), [`add_comment`](#tool-add-comment)
- [Meetings](#meetings): [`list_meetings`](#tool-list-meetings), [`get_meeting`](#tool-get-meeting), [`get_meeting_prep`](#tool-get-meeting-prep), [`add_meeting_agenda_item`](#tool-add-meeting-agenda-item), [`add_meeting_transcript`](#tool-add-meeting-transcript), [`record_meeting_decision`](#tool-record-meeting-decision), [`raise_meeting_issue`](#tool-raise-meeting-issue), [`set_meeting_summary`](#tool-set-meeting-summary), [`schedule_meeting`](#tool-schedule-meeting), [`get_meeting_transcript`](#tool-get-meeting-transcript), [`mark_meeting_held`](#tool-mark-meeting-held), [`add_meeting_notes`](#tool-add-meeting-notes), [`set_transcript_speakers`](#tool-set-transcript-speakers)
- [Your check-ins](#your-check-ins): [`get_my_meeting_checkin`](#tool-get-my-meeting-checkin), [`get_my_checkin`](#tool-get-my-checkin), [`answer_meeting_checkin`](#tool-answer-meeting-checkin), [`answer_checkin`](#tool-answer-checkin)
- [People](#people): [`list_people`](#tool-list-people), [`get_org_chart`](#tool-get-org-chart), [`get_workload`](#tool-get-workload), [`get_vision_and_values`](#tool-get-vision-and-values), [`preview_org_chart_positions`](#tool-preview-org-chart-positions), [`create_org_chart_positions`](#tool-create-org-chart-positions), [`update_position`](#tool-update-position), [`assign_person_to_position`](#tool-assign-person-to-position), [`unassign_person_from_position`](#tool-unassign-person-from-position), [`remove_empty_position`](#tool-remove-empty-position), [`update_vision_and_culture`](#tool-update-vision-and-culture)
- [Continuous improvement](#continuous-improvement): [`list_improvement_ideas`](#tool-list-improvement-ideas), [`get_improvement_dashboard`](#tool-get-improvement-dashboard), [`create_improvement_idea`](#tool-create-improvement-idea), [`update_improvement_idea`](#tool-update-improvement-idea), [`vote_improvement_idea`](#tool-vote-improvement-idea)
- [Notifications, files and reports](#notifications-files-and-reports): [`list_notifications`](#tool-list-notifications), [`list_files`](#tool-list-files), [`list_reports`](#tool-list-reports)
- [Your focus](#your-focus): [`get_my_focus`](#tool-get-my-focus)
- [myPortal: client accounts](#myportal-client-accounts): [`list_client_accounts`](#tool-list-client-accounts), [`get_client_account`](#tool-get-client-account), [`get_client_brief`](#tool-get-client-brief), [`list_client_notes`](#tool-list-client-notes), [`list_client_checkins`](#tool-list-client-checkins), [`get_client_checkin_responses`](#tool-get-client-checkin-responses), [`list_document_requests`](#tool-list-document-requests), [`list_strategy_templates`](#tool-list-strategy-templates), [`get_consultant_capacity`](#tool-get-consultant-capacity), [`get_my_timesheet`](#tool-get-my-timesheet), [`get_practice_week`](#tool-get-practice-week), [`list_timesheets_to_approve`](#tool-list-timesheets-to-approve), [`get_time_report`](#tool-get-time-report), [`get_my_day`](#tool-get-my-day), [`list_time_allocation_options`](#tool-list-time-allocation-options), [`get_productivity`](#tool-get-productivity), [`list_projects`](#tool-list-projects), [`list_billing`](#tool-list-billing), [`get_client_pnl`](#tool-get-client-pnl), [`add_client_note`](#tool-add-client-note), [`raise_client_action`](#tool-raise-client-action), [`create_document_request`](#tool-create-document-request), [`preview_strategy_template`](#tool-preview-strategy-template), [`apply_strategy_template`](#tool-apply-strategy-template), [`log_client_time`](#tool-log-client-time), [`preview_timesheet_entries`](#tool-preview-timesheet-entries), [`fill_timesheet`](#tool-fill-timesheet), [`update_time_entry`](#tool-update-time-entry), [`void_time_entry`](#tool-void-time-entry), [`submit_timesheet_week`](#tool-submit-timesheet-week), [`review_timesheet_week`](#tool-review-timesheet-week), [`start_timer`](#tool-start-timer), [`update_timer`](#tool-update-timer), [`stop_timer`](#tool-stop-timer), [`create_time_category`](#tool-create-time-category), [`create_project`](#tool-create-project), [`update_project`](#tool-update-project), [`record_invoicing`](#tool-record-invoicing), [`add_milestone`](#tool-add-milestone), [`add_add_on`](#tool-add-add-on)
- [What changed](#what-changed): [`list_status_changes`](#tool-list-status-changes), [`list_recent_changes`](#tool-list-recent-changes)
- [Search](#search): [`search`](#tool-search), [`fetch`](#tool-fetch)

<a id="account"></a>
## Account

Who the connection is, and which organizations it can act in.

<a id="tool-get-my-profile"></a>
### Get my GPS profile

`get_my_profile` · **read** · Read-only

**Who sees it:** Everyone

Returns who this connection acts as in Empiraa GPS: the person's name and email, whether the connection may only view or may also make changes, and the default organization used when a tool isn't given one. Use it to confirm which GPS account is connected.

No inputs.

<a id="tool-list-organizations"></a>
### List my organizations

`list_organizations` · **read** · Read-only

**Who sees it:** Everyone

Lists the organizations this GPS connection can act in: each one's id and name, the person's role there, whether it is a client account reached through myPortal, and whether the organization has turned AI assistants off or limited them to viewing. Other tools take the id as organization_id. Filter by part of a name with query.

| Input | Type | Required | Description |
|---|---|---|---|
| `query` | string | no | Part of an organization's name, matched ignoring case. Leave it out to list every organization. (at most 200 characters) |
| `limit` | integer | no | How many to return, at most 100. (1–100) (default `25`) |

<a id="plan-goals-and-objectives"></a>
## Plan: goals and objectives

The One Pager: goals, objectives and the scorecard.

<a id="tool-get-plan-scorecard"></a>
### Get the plan scorecard

`get_plan_scorecard` · **read** · Read-only

**Who sees it:** Everyone

**Widget contract:** `gps.scorecard/1`

Returns the organization's plan as its One Pager shows this person: each goal with its progress, status and top-level objectives (status, progress figure, current against target, owners, due date), then the objectives no listed goal shows. Filter by one goal, an owner or statuses. A plan too large for one answer is cut, keeping off-track and overdue items first; totals count what matched before any list was cut. Titles, descriptions and tag names are text people wrote. Contract gps.scorecard/1.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to read (an id from list_organizations). Leave it out to use the connection's default organization. (at most 128 characters) |
| `goal` | string | no | Just one goal: its id or title. Leave it out for the whole plan. (at most 500 characters) |
| `owner` | string | no | Only objectives assigned to this person ('me', a name, email or id), and goals assigned to them or holding one of those objectives. The One Pager has no such filter. (at most 200 characters) |
| `status` | array of one of `on_track`, `off_track`, `overdue`, `not_started`, `started`, `completed`, `archived` | no | Only objectives with these statuses, and goals with one of them or holding such an objective. The One Pager's own status filter reads statuses differently. (1–7 items) |
| `include_completed_goals` | boolean | no | Also list goals marked complete. The One Pager leaves them out, so their open objectives show as unlinked. (default `false`) |
| `max_objectives_per_goal` | integer | no | How many objectives to list under each goal (default 10). Off-track and overdue ones are kept first. (1–50) (default `10`) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |

<a id="tool-list-goals"></a>
### List goals

`list_goals` · **read** · Read-only

**Who sees it:** Everyone

Lists the goals the plan shows this person, in plan order, with each one's status, rolled-up progress, dates, priority, owners and a count of its objectives by status. Filter by words in the title, status, owner, tag or due date; completed goals only when asked for. Paged. Titles, descriptions and tag names are text people wrote.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to read (an id from list_organizations). Leave it out to use the connection's default organization. (at most 128 characters) |
| `query` | string | no | Words to find in the goal's title. (at most 200 characters) |
| `status` | array of one of `on_track`, `off_track`, `overdue`, `not_started`, `started`, `completed`, `archived` | no | Only these statuses, as the badge shows them: on_track, off_track, overdue, not_started, started, completed, archived. (1–7 items) |
| `owner` | string | no | Only goals assigned to this person: 'me', their name, email or id. (at most 200 characters) |
| `due_before` | string | no | Only goals due on or before this day, YYYY-MM-DD. |
| `due_after` | string | no | Only goals due on or after this day, YYYY-MM-DD. |
| `tag` | string | no | Only items carrying this tag, by name or id. (1–200 characters) |
| `include_completed` | boolean | no | Also list goals marked complete, which the plan leaves out. (default `false`) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-get-goal"></a>
### Get a goal

`get_goal` · **read** · Read-only

**Who sees it:** Everyone

Returns one goal as its detail panel shows it: status and why, progress rolled up from the objectives this person can see, dates, priority, owners, tags, description, whether they can only view it, and its objectives with their sub-objectives (a goal too large for one answer is cut, keeping off-track and overdue ones first). Takes the goal's id or title. The title, description, tag names and objective titles are text people wrote.

| Input | Type | Required | Description |
|---|---|---|---|
| `goal` | string | yes | The goal's id or title. (1–500 characters) |
| `organization_id` | string | no | The organization the goal is in, if known. It must be the goal's own. (at most 128 characters) |
| `include_sub_objectives` | boolean | no | List each objective's sub-objectives beneath it (default true). (default `true`) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |

<a id="tool-list-objectives"></a>
### List objectives

`list_objectives` · **read** · Read-only

**Who sees it:** Everyone

Lists the objectives the plan shows this person, in plan order: status, progress figure, current against target, owners, dates, goal, tracking period and current week or month, and whether a check-in could be recorded. Filter by goal (or 'none'), parent objective, owner, status, how it's measured, tracking period, tag, due date or title words. Paged. Titles and tag names are text people wrote.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to read (an id from list_organizations). Leave it out to use the connection's default organization. (at most 128 characters) |
| `goal` | string | no | Only objectives under this goal (its id or title), or 'none' for objectives under no goal. (at most 500 characters) |
| `parent_objective` | string | no | Only the sub-objectives of this objective (its id or title). (at most 500 characters) |
| `owner` | string | no | Only work assigned to this person: 'me', their name, email or id. (at most 200 characters) |
| `status` | array of one of `on_track`, `off_track`, `overdue`, `not_started`, `started`, `completed`, `archived` | no | Only these statuses, as the badge shows them: on_track, off_track, overdue, not_started, started, completed, archived. (1–7 items) |
| `kind` | one of `number`, `currency`, `percentage`, `status` | no | Only objectives measured this way: number, currency, percentage or status. |
| `tracking_period` | one of `total`, `weekly`, `monthly`, `yearly` | no | Only objectives tracked over this period: total, weekly, monthly or yearly. |
| `due_before` | string | no | Only objectives due on or before this day, YYYY-MM-DD. |
| `due_after` | string | no | Only objectives due on or after this day, YYYY-MM-DD. |
| `tag` | string | no | Only items carrying this tag, by name or id. (1–200 characters) |
| `query` | string | no | Words to find in the objective's title. (at most 200 characters) |
| `include_completed` | boolean | no | Include completed objectives (default true). False leaves out objectives marked complete and one-off (total) objectives that reached their target, but keeps a weekly, monthly or yearly objective that shows Completed only because this period's figure met its target: it is still being tracked. (default `true`) |
| `top_level_only` | boolean | no | Leave out sub-objectives. (default `false`) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-get-objective"></a>
### Get an objective

`get_objective` · **read** · Read-only

**Who sees it:** Everyone

Returns one objective as its detail panel shows it: current against target, progress and expected progress, status and why, dates, owners, goal and parent, its current week or month, sub-objectives, a count of its actions, tags, any integration feeding it, and whether a check-in could be recorded. Takes the objective's id or title (narrow a title with goal). The title, description and tag names are text people wrote.

| Input | Type | Required | Description |
|---|---|---|---|
| `objective` | string | yes | The objective's id or title. (1–500 characters) |
| `organization_id` | string | no | The organization the objective is in, if known. It must be the objective's own. (at most 128 characters) |
| `goal` | string | no | The goal it is under (id or title), to tell apart objectives with the same title. (at most 500 characters) |
| `include_sub_objectives` | boolean | no | List its sub-objectives (default true). (default `true`) |
| `include_actions_summary` | boolean | no | Count its open, overdue and completed actions (default true). (default `true`) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |

<a id="tool-create-goal"></a>
### Create a goal

`create_goal` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** Write connections only

Creates a goal in the organization's plan, as the goal form does: title, description, start and due dates, owners (default: the person themselves), privacy with invited people, priority and color. Needs an admin's role. A goal has no figure of its own: its progress comes from the objectives later put under it. Answers with the goal as list_goals describes it and its link. Titles and descriptions are text people wrote.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `title` | string | yes | The goal's title (1–200 characters) |
| `description` | string | no | What the goal is about (at most 5000 characters) |
| `start_date` | string | no | A calendar day, YYYY-MM-DD |
| `due_date` | string | no | A calendar day, YYYY-MM-DD |
| `owners` | array of string | no | Who the goal is assigned to: 'me', names, emails or ids (default: me) (1–20 items) (default `["me"]`) |
| `is_private` | boolean | no | Private: only its owners, the people invited and the organization's admins see it (default false) (default `false`) |
| `invited` | array of string | no | People who may also see it while it is private (at most 50 items) |
| `priority` | one of `high`, `medium`, `low` or null | no | high, medium or low |
| `color` | string | no | An accent color, #rrggbb |

<a id="tool-update-goal"></a>
### Update a goal

`update_goal` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** Write connections only

Changes a goal as its edit panel does: title, description, start and due dates, status, priority, owners (the whole list, or people added and removed), privacy and invited people, and color. Needs an admin's role. The dates must still cover the goal's objectives. A goal's progress comes from its objectives and can't be set. Takes the goal's id or exact title. Answers with what changed, before and after, and the goal as list_goals describes it.

| Input | Type | Required | Description |
|---|---|---|---|
| `goal` | string | yes | The goal: its id, or its exact title (1–300 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `title` | string | no | (1–200 characters) |
| `description` | string or null | no | Its description; null clears it |
| `start_date` | string or null | no | A calendar day, YYYY-MM-DD; null clears it |
| `due_date` | string or null | no | A calendar day, YYYY-MM-DD; null clears it |
| `status` | one of `not_started`, `started`, `on_track`, `off_track`, `completed` | no | The status the goal is set to |
| `priority` | one of `high`, `medium`, `low` or null | no | high, medium or low; null clears it |
| `owners` | array of string | no | Replaces the owners with exactly these people ('me', names, emails or ids) (at most 20 items) |
| `add_owners` | array of string | no | People to add to the owners, keeping the rest (at most 20 items) |
| `remove_owners` | array of string | no | People to take off the owners, keeping the rest (at most 20 items) |
| `is_private` | boolean | no |  |
| `invited` | array of string | no | Replaces who else may see it while it is private (at most 50 items) |
| `color` | string or null | no | An accent color, #rrggbb; null clears it |

<a id="tool-create-objective"></a>
### Create an objective

`create_objective` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** Write connections only

Creates an objective under a goal, or a sub-objective under another objective, as the objective form does: title, description, type, measurement type and target, start and due dates, tracking period, check-in frequency and day, owners (default: the person themselves) and privacy; admins may also set a weight and priority. Its dates fall within its parent's. It starts with no figure: figures are recorded as check-ins (record_objective_progress). Answers with the objective as list_objectives describes it, its link, and whether a check-in could be recorded on it.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `title` | string | yes | The objective's title (1–200 characters) |
| `description` | string | no | (at most 5000 characters) |
| `goal` | string | no | The goal it is under: its id, or its exact title (1–300 characters) |
| `parent_objective` | string | no | For a sub-objective, the objective it sits under: its id, or its exact title (1–300 characters) |
| `type` | one of `kpi`, `okr`, `rock` | no | kpi (the default), okr or rock (default `kpi`) |
| `measurement_type` | string | yes | How it is measured: one of the organization's measurement types by name ($, %, Number, a Status type or a custom one) (1–100 characters) |
| `target_value` | number | no | The figure it aims for. Left out for a Status type, which has none (at least 0) |
| `start_date` | string | yes | A calendar day, YYYY-MM-DD |
| `due_date` | string | yes | A calendar day, YYYY-MM-DD |
| `tracking_period` | one of `total`, `weekly`, `monthly`, `yearly` | no | total (the default) counts over its whole span; weekly and monthly start again at zero each week or month |
| `checkin_frequency` | one of `weekly`, `monthly`, `quarterly` | yes | How often its owners check in |
| `checkin_day` | integer | no | The day check-ins are due: 1-7 (Monday first) for weekly, the day of the month otherwise (default 1) (1–31) |
| `owners` | array of string | no | Who it is assigned to: 'me', names, emails or ids (default: me) (1–20 items) (default `["me"]`) |
| `is_private` | boolean | no | Private: only its owners, the people invited and the organization's admins see it |
| `invited` | array of string | no | People who may also see it while it is private (at most 50 items) |
| `weight` | number or null | no | Its share of its goal's progress, 0-100 (admins only; null or left out shares equally) |
| `priority` | one of `high`, `medium`, `low` or null | no | high, medium or low (admins only) |

<a id="tool-update-objective"></a>
### Update an objective

`update_objective` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** Write connections only

Changes an objective as its edit form does: title, description, type, measurement type and target, dates, tracking period, check-in frequency and day, owners (the whole list, or people added and removed), privacy, status (or auto), and where it sits (under another goal, or another objective); admins may also change its weight and priority. Its figure changes only through check-ins (record_objective_progress), and who created it never changes. Takes the objective's id or exact title. Answers with what changed, before and after, and the objective as list_objectives describes it.

| Input | Type | Required | Description |
|---|---|---|---|
| `objective` | string | yes | The objective: its id, or its exact title (1–300 characters) |
| `goal` | string | no | The goal it is under, to find it by title among that goal's objectives (1–300 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `title` | string | no | (1–200 characters) |
| `description` | string or null | no | Its description; null clears it |
| `type` | one of `kpi`, `okr`, `rock` | no |  |
| `measurement_type` | string | no | One of the organization's measurement types by name. Moving onto a Status type sets its target to 1 and its figure to not done (1–100 characters) |
| `target_value` | number | no | The figure it aims for (not for a Status type) (at least 0) |
| `start_date` | string | no | A calendar day, YYYY-MM-DD |
| `due_date` | string | no | A calendar day, YYYY-MM-DD |
| `tracking_period` | one of `total`, `weekly`, `monthly`, `yearly` | no |  |
| `checkin_frequency` | one of `weekly`, `monthly`, `quarterly` | no |  |
| `checkin_day` | integer | no | 1-7 (Monday first) for weekly, the day of the month otherwise (1–31) |
| `owners` | array of string | no | Replaces the owners with exactly these people ('me', names, emails or ids) (at most 20 items) |
| `add_owners` | array of string | no | People to add to the owners, keeping the rest (at most 20 items) |
| `remove_owners` | array of string | no | People to take off the owners, keeping the rest (at most 20 items) |
| `is_private` | boolean | no |  |
| `invited` | array of string | no | Replaces who else may see it while it is private (at most 50 items) |
| `priority` | one of `high`, `medium`, `low` or null | no | high, medium or low; null clears it (admins only) |
| `weight` | number or null | no | Its share of its goal's progress, 0-100; null shares equally (admins only) |
| `status` | one of `not_started`, `started`, `on_track`, `off_track`, `completed`, `auto` | no | A status to keep until changed, or auto for GPS to work it out from progress and dates |
| `move_to_goal` | string | no | Moves it to sit directly under this goal (its id or exact title) (1–300 characters) |
| `move_to_parent_objective` | string | no | Moves it to sit under this objective as a sub-objective (its id or exact title) (1–300 characters) |

<a id="next-90-days-and-progress"></a>
## Next 90 days and progress

What's due soon, how objectives are tracking, and check-ins.

<a id="tool-get-next-90-days"></a>
### Get the Next 90 Days board

`get_next_90_days` · **read** · Read-only

**Who sees it:** Everyone

Returns the Next 90 Days board from the plan in Empiraa GPS: the goals, objectives and actions due between today and 90 days on that this person can see, in the board's priority columns (High, Medium, Low, No Priority). In each column come goals, then objectives that aren't under a goal on the board, then actions, each by due date. A card has its status as the board's status filter reads it, its due date and days left, its owners, its tags, and a link; a goal lists the objectives on its card. A Team Member sees only the cards they are on, as on the board. Filter by type, priority, owner ("me", a name, an email or an id), status or tag. Titles, tag names and people's names are text people wrote in GPS. The board counts its days on the GPS server's clock, which window.time_zone reports. Goals carry no progress figure here: get_plan_scorecard computes it.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization, as list_organizations gives it. Leave it out to use the connection's default. |
| `type` | one of `all`, `goal`, `objective`, `action` | no | Only cards of this kind (default all). (default `all`) |
| `priority` | one of `high`, `medium`, `low`, `none` | no | Only the cards in this priority column; none is the No Priority column. |
| `owner` | string | no | Only cards this person is on, as a goal also is when they are on one of its objectives: "me", a name, an email or an id. (at most 200 characters) |
| `status` | one of `not_started`, `started`, `on_track`, `off_track`, `completed` | no | Only cards with this status, as the board's status filter reads it. |
| `tag` | string | no | Only cards with this tag (a name or an id); an action goes by its goal's or objective's tags. (at most 200 characters) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-get-objective-progress"></a>
### Get an objective's progress and forecast

`get_objective_progress` · **read** · Read-only

**Who sees it:** Everyone

**Widget contract:** `gps.kpi_trend/1`

Shows how one objective has moved and where it is heading, as its History and Forecast tabs do: its figure against target and its status badge; its check-ins and status changes, newest first and paged, each with who or what made it (a person, an integration, a meeting or an assistant); and the forecast in the Forecast tab's words, with the recent pace, the pace needed, where it ends up and, for weekly or monthly objectives, this period and the hit rate. Also says whether a check-in can be recorded on it here, and how. Takes the objective's id or title. Goals have no history of their own: get_goal shows a goal's progress. Text people wrote: the title, history notes (cut shorter when a page holds many long ones), the measurement type's name and its unit (which every *_display value carries), a status change's label, the name of an integration GPS doesn't know, and people's names.

| Input | Type | Required | Description |
|---|---|---|---|
| `objective` | string | yes | The objective's id (or search's objective:<id>), or its title. A goal id isn't an objective: goals have no history of their own. (1–500 characters) |
| `organization_id` | string | no | The organization the objective is in. Found from an id; for a title, defaults to the connection's default organization. |
| `include` | array of one of `history`, `forecast` | no | Which parts to return: history, forecast, or both (the default). (1–2 items) (default `["history","forecast"]`) |
| `history_source` | one of `all`, `person`, `integration`, `assistant` | no | As the History tab's filter: person is what people did, status changes and meeting check-ins included; integration is what integrations synced; assistant is what AI assistants did through GPS's connector (check-ins, records added from another app, status changes). (default `all`) |
| `since` | string | no | Only history entries from this day on (YYYY-MM-DD, in the organization's zone), or from this moment on (an ISO date and time with its offset, e.g. 2026-06-30T09:00:00+10:00 or 2026-06-29T23:00:00Z). (at most 40 characters) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-list-measurement-types"></a>
### List measurement types

`list_measurement_types` · **read** · Read-only

**Who sees it:** Everyone

Lists the measurement types an objective can be tracked in: money, percentages, counts with a unit, or On Track / Off Track / Complete, including the organization's own custom types, each with an example of how its values read. By default, the suggestions the measurement picker shows first (the organization's own types and the four quick types); with a query, the best matches in the picker's order; scope all lists every type by category. Text people wrote: custom types' names, unit labels, categories and descriptions (and so the examples that carry their units).

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to look in. Defaults to the connection's default organization. |
| `query` | string | no | Part of a type's name. Matches rank as the picker ranks a search: exact, starts with, a word starts with, anywhere. (at most 200 characters) |
| `kind` | one of `number`, `currency`, `percentage`, `status` | no | Only types that write values this way |
| `scope` | one of `suggested`, `custom`, `global`, `all` | no | suggested (the default): what the picker shows first, the organization's own types then the four quick types, or with a query the best 50 matches. custom: the organization's own types. global: GPS's built-in types. all: every type, by category. (default `suggested`) |
| `include_archived` | boolean | no | Also the organization's archived custom types, which the picker never offers (not with scope global). (default `false`) |
| `include_usage` | boolean | no | How many of the organization's objectives use each of its own types, as Settings shows. Not available to a Team Member. (default `false`) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-record-objective-progress"></a>
### Record a check-in on an objective

`record_objective_progress` · **write** · Changes GPS · Can't be undone by the assistant · History keeps the old value

**Who sees it:** Write connections only

Records a check-in on one objective, exactly as its check-in in GPS does: a figure that sets the value or adds to it (mode set or add); a record from another system, added once per record id (a paid invoice, a closed deal: the same id is never added twice); or, for a status objective, complete or not complete. value_kind must be the objective's own kind, as get_objective reports it, so an amount of money can't land in a count. Weekly and monthly objectives count only the current period. Parent objectives re-roll and the goal follows; goals take no check-ins of their own. Amounts are in the organization's home currency. Answers with the figure before and after, progress against target and the period. Text people wrote: the objective's, its parent's and its goal's titles, and the unit in each display value.

| Input | Type | Required | Description |
|---|---|---|---|
| `objective` | string | yes | The objective: its id (or search's objective:<id>), or its exact title. A goal takes no check-ins. (1–300 characters) |
| `goal` | string | no | The goal the objective sits under, by id or exact title, to tell apart objectives that share a title (1–300 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `value_kind` | one of `currency`, `percentage`, `number`, `status` | yes | What kind of value this is: currency (an amount in the organization's home currency), percentage (points), number (a count, in the objective's unit) or status. It must be the objective's own kind, which get_objective reports. |
| `mode` | one of `set`, `add` | no | With value: set makes the figure this value; add adds this to it, within the current period |
| `value` | number | no | A figure as a plain number (5000, not '$5k') (-1000000000000–1000000000000) |
| `record` | object | no | A record from another system, added once: give this instead of value |
| `record.source` | string | yes | The system the record comes from, e.g. HubSpot, Xero or Google Sheets (1–60 characters) |
| `record.id` | string or integer | yes | The record's id in that system (a deal, invoice or row id). One id is only ever added once to an objective. |
| `record.amount` | number | yes | What the record adds, above zero: a deal's amount, an invoice's subtotal before tax, or 1 to count it |
| `record.occurred_at` | string | no | When it happened: a day (YYYY-MM-DD) or an ISO time with its offset. Weekly and monthly objectives take only this period's. (at most 40 characters) |
| `record.label` | string | no | What the record is (a deal's name, an invoice number), kept as the check-in's note (at most 200 characters) |
| `status` | one of `complete`, `not_complete`, `on_track`, `off_track` | no | For a status objective: complete or not_complete. On Track and Off Track are its status, not a check-in. |
| `notes` | string | no | A note to keep with the change, at most 1,000 characters (at most 1000 characters) |
| `confirm_large` | boolean | no | Says an add or record bigger than the objective's whole target is meant: a count objective refuses one otherwise |

<a id="tool-preview-progress-batch"></a>
### Preview a batch of check-ins

`preview_progress_batch` · **preview** · Read-only · Previews `record_progress_batch`, changes nothing

**Who sees it:** Write connections only

Shows what up to 25 check-ins would do, without changing anything: each item (a figure, a record or a status, as record_objective_progress takes them) with its objective's figure before and after, in order, so two items on one objective build on each other; each item GPS would refuse, and why; and warnings worth a look. Answers with a preview token, good for 15 minutes and one use, which record_progress_batch applies exactly as previewed. Text people wrote: objective titles, and the unit in each display value.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `items` | array of object | yes | The check-ins, in the order they apply: at most 25 (1–25 items) |
| `items[].ref` | string | no | Your own name for this item (a row number, a deal), given back with its result (at most 100 characters) |
| `items[].objective` | string | yes | The objective: its id (or search's objective:<id>), or its exact title. A goal takes no check-ins. (1–300 characters) |
| `items[].goal` | string | no | The goal the objective sits under, by id or exact title, to tell apart objectives that share a title (1–300 characters) |
| `items[].value_kind` | one of `currency`, `percentage`, `number`, `status` | yes | What kind of value this is: currency (an amount in the organization's home currency), percentage (points), number (a count, in the objective's unit) or status. It must be the objective's own kind, which get_objective reports. |
| `items[].mode` | one of `set`, `add` | no | With value: set makes the figure this value; add adds this to it, within the current period |
| `items[].value` | number | no | A figure as a plain number (5000, not '$5k') (-1000000000000–1000000000000) |
| `items[].record` | object | no | A record from another system, added once: give this instead of value |
| `items[].record.source` | string | yes | The system the record comes from, e.g. HubSpot, Xero or Google Sheets (1–60 characters) |
| `items[].record.id` | string or integer | yes | The record's id in that system (a deal, invoice or row id). One id is only ever added once to an objective. |
| `items[].record.amount` | number | yes | What the record adds, above zero: a deal's amount, an invoice's subtotal before tax, or 1 to count it |
| `items[].record.occurred_at` | string | no | When it happened: a day (YYYY-MM-DD) or an ISO time with its offset. Weekly and monthly objectives take only this period's. (at most 40 characters) |
| `items[].record.label` | string | no | What the record is (a deal's name, an invoice number), kept as the check-in's note (at most 200 characters) |
| `items[].status` | one of `complete`, `not_complete`, `on_track`, `off_track` | no | For a status objective: complete or not_complete. On Track and Off Track are its status, not a check-in. |
| `items[].notes` | string | no | A note to keep with the change, at most 1,000 characters (at most 1000 characters) |
| `items[].confirm_large` | boolean | no | Says an add or record bigger than the objective's whole target is meant: a count objective refuses one otherwise |

<a id="tool-record-progress-batch"></a>
### Apply a previewed batch of check-ins

`record_progress_batch` · **write** · Changes GPS · Can't be undone by the assistant · History keeps the old value

**Who sees it:** Write connections only

Records the check-ins preview_progress_batch showed, exactly as previewed, from its token: items the preview refused are left out, and skip leaves out more. If any objective changed since the preview, nothing is applied. Items apply in order, each on its own; one that fails stops the rest, and every item is reported as applied, skipped, refused in the preview, failed or not attempted. A token is used once. Text people wrote: objective titles, and the unit in each display value.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `preview_token` | string | yes | The token preview_progress_batch gave |
| `skip` | array of integer | no | Items of the preview to leave out, by their index (at most 25 items) |

<a id="keeping-a-kpi-in-sync"></a>
## Keeping a KPI in sync

GPS's own sync from a connected Xero, HubSpot, Google Sheets or Excel account, set up from chat: GPS keeps the figure current afterwards.

<a id="tool-list-sync-options"></a>
### List ways to keep a KPI in sync

`list_sync_options` · **read** · Read-only

**Who sees it:** Everyone

For one objective: which of the organization's accounts are connected in GPS (Xero, HubSpot, Google Sheets, Excel), the sync recipes that fit how it is measured (each with what it counts, whether it sets the figure or adds each record once, and the parameters it needs), and whether it is synced now, and how. Changes nothing and calls no outside account. Text people wrote: the objective's title.

| Input | Type | Required | Description |
|---|---|---|---|
| `objective` | string | yes | The objective: its id (or search's objective:<id>), or its exact title (1–300 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |

<a id="tool-preview-objective-sync"></a>
### Preview keeping a KPI in sync

`preview_objective_sync` · **preview** · Reads a connected account live (may renew its sign-in) · Previews `set_objective_sync`, changes nothing

**Who sees it:** Write connections only

Runs a sync recipe over the connected account's records now (it reads Xero, HubSpot, Google Sheets or Excel live, which may renew that account's sign-in) and shows, without changing anything in GPS: the figure the objective would show, against its target and period; whether it sets the figure or adds each record once; some of the records it counts; and anything worth a look. Answers with a preview token, good for 15 minutes and one use, which set_objective_sync applies exactly as previewed. Text people wrote: the objective's title, record fields.

| Input | Type | Required | Description |
|---|---|---|---|
| `objective` | string | yes | The objective: its id (or search's objective:<id>), or its exact title (1–300 characters) |
| `recipe` | one of `xero_revenue_invoiced`, `xero_payments_received`, `xero_receivables_outstanding`, `xero_receivables_overdue`, `xero_invoices_paid_count`, `xero_invoices_raised_count`, `xero_bills_outstanding`, `hubspot_won_deal_value`, `hubspot_deals_won_count`, `hubspot_open_pipeline_value`, `hubspot_new_deals_count`, `hubspot_new_contacts_count`, `hubspot_new_leads_count`, `hubspot_meetings_booked_count`, `google_sheets_last_value`, `google_sheets_column_total`, `google_sheets_row_value`, `google_sheets_row_count`, `excel_last_value`, `excel_column_total`, `excel_row_value`, `excel_row_count` | yes | The recipe, by the id list_sync_options gives |
| `params` | object | no | The recipe's parameters by name, as list_sync_options lists them (a deal stage, a spreadsheet, a column…) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |

<a id="tool-set-objective-sync"></a>
### Keep a KPI in sync from a connected account

`set_objective_sync` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** Write connections only

Sets up the sync preview_objective_sync showed, from its token: GPS saves it as its own integration sync (as the objective's Integrations tab would), writes the figure the preview showed, and turns auto-sync on, so GPS keeps the figure current by itself from then on. Refused if the objective's sync, target or measurement changed since the preview. Check-ins on the objective are refused once it is synced. Undone in GPS. Text people wrote: the objective's title.

| Input | Type | Required | Description |
|---|---|---|---|
| `preview_token` | string | yes | The token preview_objective_sync gave |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |

<a id="tool-stop-objective-sync"></a>
### Stop keeping a KPI in sync

`stop_objective_sync` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** Write connections only

Turns off an objective's auto-sync, so its figure stays where it is and check-ins are taken again; with clear_formula, also removes what it was synced from (otherwise GPS keeps it, and Sync now in GPS still runs it). Changes nothing when the objective isn't synced. Undone in GPS. Text people wrote: the objective's title.

| Input | Type | Required | Description |
|---|---|---|---|
| `objective` | string | yes | The objective: its id (or search's objective:<id>), or its exact title (1–300 characters) |
| `clear_formula` | boolean | no | Also remove what it was synced from, so it isn't synced even by Sync now in GPS (false by default: auto-sync off, the formula kept) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |

<a id="actions"></a>
## Actions

The Actions board.

<a id="tool-list-actions"></a>
### List actions

`list_actions` · **read** · Read-only

**Who sees it:** Everyone

**Widget contract:** `gps.action_board/1`

Lists the actions on the Actions board in Empiraa GPS, as the board shows them to this person, a page at a time: open work by default (state done for completed or canceled, all for both), with the board's counts of open, overdue, due this week, undated and done. Filters: status, mine, assignee (names, emails, ids, "me", "unassigned"), objective (id, name or "none"), tags, due (overdue, this_week, no_date, or a from/to range of days) and query (words in the title, description, notes, objective title or tag names). Overdue and due dates count from the organization's today. A repeating action appears as a new row for each occurrence. Titles and descriptions are text people wrote. A page of long rows can hold fewer than limit; next_cursor continues it.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to list; the default one when left out |
| `state` | one of `open`, `done`, `all` | no | open (the default) is work still to do; done is completed or canceled; all is both, open first (default `open`) |
| `status` | array of one of `to_do`, `started`, `on_track`, `off_track`, `completed`, `cancelled` | no | Any of these statuses; to_do is Not Started (at most 6 items) |
| `mine` | boolean | no | Only actions assigned to this person (not ones they created) |
| `assignee` | array of string | no | Assigned to any of these people, by name, email or id; "me" for this person, "unassigned" for actions assigned to nobody (1–20 items) |
| `objective` | string | no | Only one objective's actions, by id or name; "none" for actions linked to no objective (1–300 characters) |
| `tags` | array of string | no | Carrying every one of these tags, by name or id (1–10 items) |
| `due` | one of `overdue`, `this_week`, `no_date` or object | no | overdue and this_week (today and the next six days) count open work only; no_date; or a range of due days, from and to inclusive |
| `due.from` | string | no |  |
| `due.to` | string | no |  |
| `query` | string | no | Words to find in the title, description, notes, objective title or tag names (at most 200 characters) |
| `sort` | one of `due_date`, `priority`, `title`, `created` | no | How open actions are ordered (due_date, the default, puts undated ones last). Done actions are always most recently closed first. (default `due_date`) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-get-action"></a>
### Get an action

`get_action` · **read** · Read-only

**Who sees it:** Everyone

Returns one action from Empiraa GPS by id or title: its status, priority, due date, assignees, objective and tags as the Actions board shows them (an archived action, off the board, has state archived), plus its description and notes (text people wrote), start date, goal, the meeting it was captured in, how it repeats, and its latest comments. A title is matched among the actions the board lists for this person.

| Input | Type | Required | Description |
|---|---|---|---|
| `action` | string | yes | The action's id, or its title (1–300 characters) |
| `organization_id` | string | no | The organization the action is in. Optional: an id decides it. |

<a id="tool-create-action"></a>
### Create an action

`create_action` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** Write connections only

Creates an action in Empiraa GPS: a piece of work with a title, an optional description, assignees, a due date (from today on), a priority, a starting status (Not Started, Started, On Track or Off Track) and an optional weekly or monthly repeat, filed under an objective (its id or exact name) and optionally captured in a meeting (its id or exact title). Under an objective, an action given no assignees takes the objective's owners, and one given no due date takes the objective's, as GPS does. A private action is seen only by its creator. Assignees are people in the organization: 'me', a name, an email or an id. Names are matched exactly, never guessed. Returns the action as the Actions board shows it, with a link that opens it.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `title` | string | yes | What is to be done (1–300 characters) |
| `description` | string | no | (at most 5000 characters) |
| `objective` | string | no | The objective it serves: its id, or its exact name as the person's objective list shows it (1–300 characters) |
| `assignees` | array of string | no | Who does it: 'me', names, emails or ids. Left out under an objective, it takes the objective's owners (at most 20 items) |
| `due_date` | string or null | no | The day it is due, YYYY-MM-DD, from today on. Left out under an objective, it takes the objective's due date |
| `priority` | one of `high`, `medium`, `low` | no | high, medium or low; medium when left out |
| `status` | one of `to_do`, `started`, `on_track`, `off_track` | no | to_do is Not Started; started when left out |
| `repeat` | object | no | A repeating action: completing it creates the next occurrence |
| `repeat.frequency` | one of `weekly`, `monthly` | yes | How often it comes round again |
| `repeat.weekday` | one of `monday`, `tuesday`, `wednesday`, `thursday`, `friday`, `saturday`, `sunday` | no | For weekly: the day each occurrence is due |
| `repeat.day_of_month` | integer | no | For monthly: the day of the month each occurrence is due (a shorter month uses its last day) (1–31) |
| `private` | boolean | no | Only its creator can see it |
| `meeting` | string | no | The meeting it was captured in: its id, or its exact title (1–300 characters) |

<a id="tool-preview-actions-batch"></a>
### Preview creating actions

`preview_actions_batch` · **preview** · Read-only · Previews `create_actions_batch`, changes nothing

**Who sees it:** Write connections only

Previews creating up to 25 actions in Empiraa GPS at once (from meeting notes, say) without creating anything. Each item takes create_action's fields and is checked as create_action checks it; the preview shows what each would create, what it would take from its objective (owners, due date), and warnings such as an action with the same title already captured in the same meeting. Returns a preview_token that create_actions_batch applies, once, within 15 minutes: it creates exactly what was previewed, or nothing if an item's objective or meeting has changed since. No token is issued when no item can be created.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `items` | array of object | yes | The actions to create, at most 25 (1–25 items) |
| `items[].ref` | string | no | Your own label for the item, repeated back in the results (at most 100 characters) |
| `items[].title` | string | yes | What is to be done (1–300 characters) |
| `items[].description` | string | no | (at most 5000 characters) |
| `items[].objective` | string | no | The objective it serves: its id, or its exact name as the person's objective list shows it (1–300 characters) |
| `items[].assignees` | array of string | no | Who does it: 'me', names, emails or ids. Left out under an objective, it takes the objective's owners (at most 20 items) |
| `items[].due_date` | string or null | no | The day it is due, YYYY-MM-DD, from today on. Left out under an objective, it takes the objective's due date |
| `items[].priority` | one of `high`, `medium`, `low` | no | high, medium or low; medium when left out |
| `items[].status` | one of `to_do`, `started`, `on_track`, `off_track` | no | to_do is Not Started; started when left out |
| `items[].repeat` | object | no | A repeating action: completing it creates the next occurrence |
| `items[].repeat.frequency` | one of `weekly`, `monthly` | yes | How often it comes round again |
| `items[].repeat.weekday` | one of `monday`, `tuesday`, `wednesday`, `thursday`, `friday`, `saturday`, `sunday` | no | For weekly: the day each occurrence is due |
| `items[].repeat.day_of_month` | integer | no | For monthly: the day of the month each occurrence is due (a shorter month uses its last day) (1–31) |
| `items[].private` | boolean | no | Only its creator can see it |
| `items[].meeting` | string | no | The meeting it was captured in: its id, or its exact title (1–300 characters) |

<a id="tool-create-actions-batch"></a>
### Create previewed actions

`create_actions_batch` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** Write connections only

Creates the actions a preview_actions_batch preview showed, from its preview_token, in order, leaving out the items the preview refused and any indexes in skip. Each is created exactly as previewed, with the assignees and due date it showed. If an item's objective or meeting has changed since the preview, nothing is created and what changed is listed. A preview is applied once. Reports every item: applied (with a link that opens it), skipped, refused in the preview, failed, or not attempted after a failure.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `preview_token` | string | yes | The preview_token preview_actions_batch returned |
| `skip` | array of integer | no | Indexes of previewed items to leave out (at most 25 items) |

<a id="tool-update-action"></a>
### Update an action

`update_action` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** Write connections only

Changes an action in Empiraa GPS, found by its id or exact title: its title, description, notes, objective, status (including completing or canceling it), priority, start and due dates, assignees (replace them, or add and remove some), weekly or monthly repeat, or privacy. Only the fields given change, and giving what it already says changes nothing. Completing a repeating action creates its next occurrence, as GPS does. Only an action's creator can make it private, and an archived action can't be changed. Returns the action with each field that changed, before and after.

| Input | Type | Required | Description |
|---|---|---|---|
| `action` | string | yes | The action: its id, or its exact title (1–300 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `title` | string | no | (1–300 characters) |
| `description` | string or null | no | Null or empty clears it |
| `notes` | string or null | no | Null or empty clears them |
| `objective` | string | no | Move it under this objective: its id, or its exact name (1–300 characters) |
| `status` | one of `started`, `on_track`, `off_track`, `completed`, `cancelled` | no | completed finishes it (a repeating action then creates its next occurrence); `cancelled` abandons it |
| `priority` | one of `high`, `medium`, `low` | no | high, medium or low |
| `due_date` | string or null | no | YYYY-MM-DD; null clears it |
| `start_date` | string or null | no | YYYY-MM-DD; null clears it |
| `assignees` | array of string | no | Replaces the assignees with exactly these people ('me', names, emails or ids) (at most 20 items) |
| `add_assignees` | array of string | no | People to add to the assignees, keeping the rest (at most 20 items) |
| `remove_assignees` | array of string | no | People to take off the assignees, keeping the rest (at most 20 items) |
| `repeat` | object or null | no | A weekly or monthly repeat; null stops it repeating |
| `repeat.frequency` | one of `weekly`, `monthly` | yes | How often it comes round again |
| `repeat.weekday` | one of `monday`, `tuesday`, `wednesday`, `thursday`, `friday`, `saturday`, `sunday` | no | For weekly: the day each occurrence is due |
| `repeat.day_of_month` | integer | no | For monthly: the day of the month each occurrence is due (a shorter month uses its last day) (1–31) |
| `private` | boolean | no | Only an action's creator can make it private |

<a id="comments"></a>
## Comments

Comments on goals, objectives, actions, meetings and ideas.

<a id="tool-list-comments"></a>
### List comments

`list_comments` · **read** · Read-only

**Who sees it:** Everyone

Lists the comments on one objective, goal, action, meeting or improvement idea in Empiraa GPS, oldest first: who wrote each, when, and what they wrote (body, and attachment names, are text people wrote). Replies are included, each with the parent_id of the comment it answers. Name exactly one of objective_id, goal_id, action_id, meeting_id or idea_id. A meeting's comments are mostly its agenda discussion, each such comment with the agenda_item_id it is on; agenda_item_id with meeting_id lists one item's. since narrows to recent comments; response_format detailed returns longer bodies, reply counts and who each comment mentions. A page of long comments can hold fewer than limit; next_cursor continues it.

| Input | Type | Required | Description |
|---|---|---|---|
| `objective_id` | string | no | The id of the objective whose comments to list (1–128 characters) |
| `goal_id` | string | no | The id of the goal whose comments to list (1–128 characters) |
| `action_id` | string | no | The id of the action whose comments to list (1–128 characters) |
| `meeting_id` | string | no | The id of the meeting whose comments to list: its agenda discussion, and any comment on the meeting itself (1–128 characters) |
| `idea_id` | string | no | The id of the improvement idea whose comments to list (1–128 characters) |
| `agenda_item_id` | string | no | With meeting_id, only the comments on this agenda item (1–128 characters) |
| `since` | string | no | Only comments posted at or after this moment: an ISO 8601 date-time, or a date (YYYY-MM-DD, meaning midnight UTC) (at most 40 characters) |
| `organization_id` | string | no | The organization the item is in. Optional: the item decides it. |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-add-comment"></a>
### Add a comment

`add_comment` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** Write connections only

Adds a comment, as this person, to one objective, goal, action, meeting or improvement idea in Empiraa GPS, where the app's own thread shows it. Name exactly one of objective, goal, action or idea (by id or exact title) or meeting (by id). On a meeting, agenda_item_id puts it in that agenda item's discussion (get_meeting lists the items), and hidden_until_meeting, before the meeting starts, has GPS show it only to its author until then; it isn't private, since GPS sends every meeting comment's text live to everyone in the organization who has GPS open. reply_to answers a comment on an objective, goal or meeting (list_comments gives their ids). Text only: no attachments, and nobody is mentioned, so it notifies no one by name; a meeting's invitees are notified in the app, as the app does for any meeting comment. Bodies are up to 4,000 characters, 2,000 on an idea. An identical comment repeated within ten minutes isn't posted twice.

| Input | Type | Required | Description |
|---|---|---|---|
| `objective` | string | no | The objective to comment on: its id, or its exact title (1–300 characters) |
| `goal` | string | no | The goal to comment on: its id, or its exact title (1–300 characters) |
| `action` | string | no | The action to comment on: its id, or its exact title (1–300 characters) |
| `meeting` | string | no | The meeting to comment on, by its id (list_meetings gives it, or search's meeting:<id>); meetings repeat under one title (1–300 characters) |
| `idea` | string | no | The improvement idea to comment on: its id, or its exact title (1–300 characters) |
| `agenda_item_id` | string | no | With meeting: the agenda item whose discussion it joins, by the id get_meeting gives it. Left out, it's on the meeting itself (1–200 characters) |
| `reply_to` | string (uuid) | no | The comment this answers, by the id list_comments gives it: on an objective, a goal or a meeting |
| `body` | string | yes | What to say, as plain text: at most 4,000 characters, 2,000 on an improvement idea (1–4000 characters) |
| `hidden_until_meeting` | boolean | no | On a meeting that hasn't started: GPS shows it only to its author until the meeting starts. It isn't private: as with every meeting comment, GPS sends its text live to everyone in the organization who has GPS open |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |

<a id="meetings"></a>
## Meetings

Meetings, their prep, agendas, decisions, issues and summaries, and a notetaker's record of one: held, its notes, its transcript.

<a id="tool-list-meetings"></a>
### List meetings

`list_meetings` · **read** · Read-only

**Who sees it:** Everyone

Lists the meetings in one organization that the person can see on the GPS Meetings page. By default, those still to come from the start of today, soonest first; when=today, past (newest first) or all changes the time, and from/to (days in the person's time zone), status (missed included), type, query and mine narrow it. To find the meeting a notetaker recorded: starts_near (the recording's start; within two hours either side, closest first), attendee (someone on it, a guest's email included), meeting_url (its join link) and calendar_event_id. Each meeting has the status the page shows, when it is in the person's time zone, its organizer and a link; detailed adds who is invited (guests by email too), its join link and the start of its description. Titles, descriptions and locations are written by people. get_meeting reads one meeting in full.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to look in, from list_organizations. Left out, the connection's default organization is used. (at most 200 characters) |
| `when` | one of `upcoming`, `today`, `past`, `all` | no | upcoming (the default, unless starts_near is given): not finished (scheduled, running or paused) and scheduled from the start of today, soonest first. today: every meeting on the person's calendar day. past: scheduled before now, newest first. all (the default with starts_near): any time, newest first (the newest 2000 unless from or to is given). |
| `from` | string | no | Only meetings scheduled on or after this day (YYYY-MM-DD, the person's time zone) |
| `to` | string | no | Only meetings scheduled on or before this day (YYYY-MM-DD, the person's time zone) |
| `status` | array of one of `scheduled`, `in_progress`, `paused`, `completed`, `cancelled`, `resolved_async`, `missed` | no | Only these, matched against display_status (so missed finds scheduled meetings whose time has passed) (1–7 items) |
| `type` | string | no | Only meetings of exactly this type, as the Meetings page's type filter (1–200 characters) |
| `query` | string | no | Only meetings whose title, type or description contains this (1–200 characters) |
| `mine` | boolean | no | true: only meetings the person organizes or is invited to |
| `attendee` | string | no | Only meetings this person organizes or is invited to: 'me', a name, an email or an id of someone in the organization, or the email of a guest from outside it (1–254 characters) |
| `starts_near` | string | no | Only meetings scheduled to start within two hours of this moment (ISO 8601; without an offset, a time in the person's time zone), such as when a recording started; closest first, each with minutes_from_starts_near (1–40 characters) |
| `meeting_url` | string | no | Only meetings joined at this link (compared without its query string or the www, so a Zoom link with or without its passcode matches) (1–2000 characters) |
| `calendar_event_id` | string | no | Only the meeting GPS synced with this calendar event, by the event's id in Google or Microsoft calendar (1–1024 characters) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-get-meeting"></a>
### Get a meeting

`get_meeting` · **read** · Read-only

**Who sees it:** Everyone

Reads one meeting the person can see in GPS: when and where, who is invited, its agenda (with each item's notes), its own notes, decisions and issues, its saved summary (for a meeting resolved from its check-ins, the async digest), which transcripts it has, and what the person may change on it (can). A finished meeting also has its recap: the objectives and actions it covered, its Q&A, and what became of the previous meeting's actions; include_recap reads it for one still to finish. A decision's objective is named only when the person could open that objective. Titles, notes, decisions, issues, questions and summaries are written by people.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to look in, from list_organizations. Left out, the connection's default organization is used. (at most 200 characters) |
| `meeting_id` | string | yes | The meeting's id, as list_meetings returns it (or search's meeting:<id>) (1–200 characters) |
| `include_recap` | boolean | no | Read the recap (what it produced) even though the meeting hasn't finished; a finished meeting always has it |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |

<a id="tool-get-meeting-prep"></a>
### Prepare for a meeting

`get_meeting_prep` · **read** · Read-only

**Who sees it:** Everyone

**Widget contract:** `gps.meeting_prep/1`

The pre-read for one meeting the person can see, as its Hub in GPS shows it: the agenda, where the KPIs and objectives it covers stand now, and who has checked in, with their answers where the meeting's check-in lets this person read them (the organizer always; people on the meeting as its setting allows; an admin who isn't on it sees only who has checked in). detailed adds the issues still open on it. Agenda items, titles and check-in answers are written by people. For a meeting that has finished, get_meeting has its record.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to look in, from list_organizations. Left out, the connection's default organization is used. (at most 200 characters) |
| `meeting_id` | string | yes | The meeting's id, as list_meetings returns it (or search's meeting:<id>) (1–200 characters) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |

<a id="tool-add-meeting-agenda-item"></a>
### Add a meeting agenda item

`add_meeting_agenda_item` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** Write connections only

Adds one item to a meeting's agenda in GPS, as its organizer does in the meeting's Hub: a title, its minutes (15 unless given), optional notes, what kind of item it is, and where it goes (after another item, or at the end). A scorecard or objectives item may name which of the meeting's own objectives it is about. Only the meeting's organizer can, and only while the meeting is still scheduled. An item with the same title as one already on the agenda isn't added twice. Nobody beyond the meeting is notified. The answer says how long the agenda now runs against the meeting's length.

| Input | Type | Required | Description |
|---|---|---|---|
| `meeting_id` | string | yes | The meeting's id, as list_meetings returns it (or search's meeting:<id>) (1–200 characters) |
| `title` | string | yes | What the item is, as the agenda shows it (1–200 characters) |
| `minutes` | integer | no | How long it gets, in whole minutes (15 unless given) (1–480) (default `15`) |
| `notes` | string | no | What people should know before it, as the Hub's notes on an item (at most 1000 characters) |
| `kind` | one of `discussion`, `checkin_round`, `scorecard`, `objectives`, `issues`, `decision`, `poll`, `retro` | no | What the item is for, which decides what the meeting opens when it reaches it: discussion (the default), checkin_round, scorecard, objectives, issues, decision, poll or retro |
| `objectives` | array of string | no | For a scorecard or objectives item: which of the meeting's own objectives it is about (get_meeting_prep lists them), by id or exact title; left out, it is about all of them (at most 20 items) |
| `after_item` | string | no | Put it straight after this item (its id from get_meeting, or its exact title); at the end otherwise (1–200 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |

<a id="tool-add-meeting-transcript"></a>
### Add a meeting transcript

`add_meeting_transcript` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** Write connections only

Adds a meeting's transcript to GPS for people to review: plain text, WebVTT or SRT, as a notetaker exports it. Anyone who can see the meeting may add one. It lands in the meeting's Transcript tab, with the speakers matched to people in the organization where their names match; nothing is taken from it (no actions, decisions or summary) until a person reviews it there. The same text added to the same meeting twice is refused. The answer never repeats the text.

| Input | Type | Required | Description |
|---|---|---|---|
| `meeting_id` | string | yes | The meeting's id, as list_meetings returns it (or search's meeting:<id>) (1–200 characters) |
| `text` | string | yes | The transcript as the notetaker exported it, in the format named (1–1000000 characters) |
| `format` | one of `vtt`, `srt`, `text` | no | text (plain lines, "Name: what they said"; the default), vtt (WebVTT) or srt (default `text`) |
| `title` | string | no | What to call it in the meeting's Transcript tab (at most 200 characters) |
| `source_app` | string | no | The app it came from (a notetaker's name), shown with it in GPS (at most 60 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |

<a id="tool-record-meeting-decision"></a>
### Record a meeting decision

`record_meeting_decision` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** Write connections only

Records a decision a meeting made, as its organizer does in GPS: what was decided, any details, who owns it, the objective it concerns and the agenda item it was made under. Only the meeting's organizer can, once the meeting has started (or after it ends). Before a meeting starts, raise_meeting_issue and add_meeting_agenda_item are how something gets onto it. An objective is named only if the person can open it.

| Input | Type | Required | Description |
|---|---|---|---|
| `meeting_id` | string | yes | The meeting's id, as list_meetings returns it (or search's meeting:<id>) (1–200 characters) |
| `title` | string | yes | What was decided (1–300 characters) |
| `details` | string | no | Anything else worth keeping with it (at most 2000 characters) |
| `owner` | string | no | Who owns carrying it out: 'me', their name, email or id (1–200 characters) |
| `objective` | string | no | The objective it concerns, by id or exact title (1–300 characters) |
| `agenda_item` | string | no | The agenda item it was made under: its id from get_meeting, or its exact title (1–200 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |

<a id="tool-raise-meeting-issue"></a>
### Raise a meeting issue

`raise_meeting_issue` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** Write connections only

Raises an issue on a meeting's issues list in GPS, or parks a topic there for later (kind parked), as people on the meeting do: a title, any details, and the agenda item it belongs to. Only people invited to the meeting (its organizer included) can, until it ends. An issue with the same title still open on the meeting isn't raised twice.

| Input | Type | Required | Description |
|---|---|---|---|
| `meeting_id` | string | yes | The meeting's id, as list_meetings returns it (or search's meeting:<id>) (1–200 characters) |
| `title` | string | yes | What the issue is (1–200 characters) |
| `details` | string | no | Anything else people need to know about it (at most 2000 characters) |
| `kind` | one of `issue`, `parked` | no | issue (to work through; the default), or parked (off-topic, kept for later) (default `issue`) |
| `agenda_item` | string | no | The agenda item it belongs to: its id from get_meeting, or its exact title (1–200 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |

<a id="tool-set-meeting-summary"></a>
### Set a meeting summary

`set_meeting_summary` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** Write connections only

Writes the summary of a meeting that has been held and ended, as its organizer does in GPS, replacing any summary it had. Only the meeting's organizer can; a meeting resolved from its check-ins has its digest instead, and takes no summary. Nobody is notified or emailed: people see it when they open the meeting. Sending the same summary again changes nothing.

| Input | Type | Required | Description |
|---|---|---|---|
| `meeting_id` | string | yes | The meeting's id, as list_meetings returns it (or search's meeting:<id>) (1–200 characters) |
| `summary` | string | yes | The meeting's summary, at most 20,000 characters; it replaces any summary it had (1–20000 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |

<a id="tool-schedule-meeting"></a>
### Schedule a meeting

`schedule_meeting` · **write** · Changes GPS · Adds, never replaces · Emails people

**Who sees it:** Write connections only

Schedules a new meeting in GPS, organized by the person, as the Schedule Meeting form does: a title, when it starts (a time where the organization is, or with an offset), how long it runs (15 to 480 minutes; 60 unless given), the people in the organization to invite, an agenda (otherwise the usual opening, discussion and wrap-up), the objectives it is about, its type, and a room or a video link. Only people in the organization can be invited, and it is one meeting, not a series. This reaches people: the invitation goes now, in GPS and by email; its check-in goes out two days before it starts (straight away for a meeting sooner than that), with reminders, unless checkin_emails is manual; meeting reminders follow; and attendees who sync their calendar get a copy. The answer lists exactly what goes out, to whom and when. A meeting the person already has with the same title and start isn't scheduled twice.

| Input | Type | Required | Description |
|---|---|---|---|
| `title` | string | yes | What the meeting is called (1–200 characters) |
| `description` | string | no | What it is for: it goes with the invitation and the calendar copies (at most 2000 characters) |
| `starts_at` | string | yes | A time: YYYY-MM-DDTHH:MM where the organization is, or ISO 8601 with an offset (at most 40 characters) |
| `duration_minutes` | integer | no | How long it runs, 15 to 480 minutes (60 unless given) (15–480) (default `60`) |
| `attendees` | array of string | no | The people in the organization to invite: names, emails or ids. Its organizer is the person themselves, who isn't invited to their own meeting (at most 100 items) (default `[]`) |
| `agenda` | array of object | no | The items it starts with, in order; left out (or empty), GPS's opening, main discussion and wrap-up (at most 40 items) |
| `agenda[].title` | string | yes | What the item is (1–200 characters) |
| `agenda[].minutes` | integer | yes | How long it gets, in whole minutes (1–480) |
| `agenda[].kind` | one of `discussion`, `checkin_round`, `scorecard`, `objectives`, `issues`, `decision`, `poll`, `retro` | no | What the item is for: discussion (the default), checkin_round, scorecard, objectives, issues, decision, poll or retro |
| `objectives` | array of string | no | The objectives it is about, by id or exact title (at most 20 items) |
| `meeting_type` | string | no | Its type, as the Meetings page groups them ("Meeting" unless given) (at most 100 characters) |
| `location` | string | no | Where it is held, for a meeting in a room (at most 300 characters) |
| `video_url` | string (uri) | no | The link to join it, for a meeting online (at most 2000 characters) |
| `checkin_emails` | one of `automatic`, `manual` | no | automatic (the default): GPS sends its check-in to the attendees before it, and reminds them. manual: the organizer sends it from the meeting's Hub (default `automatic`) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |

<a id="tool-get-meeting-transcript"></a>
### Read a meeting transcript

`get_meeting_transcript` · **read** · Read-only

**Who sees it:** Everyone

Reads one of a meeting's transcripts in GPS, a page of lines at a time: who said each line (as the transcript names them), when in the recording, and what they said, with every speaker and the person in the organization GPS has them as. The newest transcript unless transcript_id names another; speaker keeps one speaker's lines. Anyone who can see the meeting may read it. Every line is text people said.

| Input | Type | Required | Description |
|---|---|---|---|
| `meeting_id` | string | yes | The meeting's id, as list_meetings returns it (or search's meeting:<id>) (1–200 characters) |
| `transcript_id` | string | no | Which of the meeting's transcripts (other_transcripts lists them); the newest when left out (1–200 characters) |
| `speaker` | string | no | Only the lines this speaker said, named as the transcript names them (1–120 characters) |
| `organization_id` | string | no | The organization to look in, from list_organizations. Left out, the connection's default organization is used. (at most 200 characters) |
| `limit` | integer | no | How many lines to return, 1 to 500 (default 200). (1–500) (default `200`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-mark-meeting-held"></a>
### Mark a meeting held

`mark_meeting_held` · **write** · Changes GPS · Can't be undone by the assistant · Emails people

**Who sees it:** Write connections only

Marks a meeting GPS still has as scheduled (shown as missed once its time has passed) as held and ended, with the start and end its recording gives, as its organizer ending it in GPS does. Only its organizer can; a meeting started in GPS is ended there. GPS then does what it does when any meeting ends: its check-out goes to the people invited, in GPS and by email, if its organizer turned one on; consultant time is recorded for consultants who joined it in GPS; and it takes decisions and its summary, but no more issues or agenda items. Nobody else in the organization is notified. It can't be undone: GPS never moves a completed meeting back. The answer says what went out.

| Input | Type | Required | Description |
|---|---|---|---|
| `meeting_id` | string | yes | The meeting's id, as list_meetings returns it (or search's meeting:<id>) (1–200 characters) |
| `started_at` | string | yes | When it started, from the recording: ISO 8601 with an offset (2026-10-04T09:02:00+10:00), or a time where the organization is (1–40 characters) |
| `ended_at` | string | yes | When it ended, from the recording, written as started_at is (1–40 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |

<a id="tool-add-meeting-notes"></a>
### Add meeting notes

`add_meeting_notes` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** Write connections only

Adds notes to a meeting in GPS, after any notes already there, under a first line naming the app they came from (a notetaker's, say): on one agenda item, or on the meeting itself. An agenda item's notes are its organizer's, as the agenda is, and take additions before the meeting starts or after it ends, never while it runs in GPS. The meeting's own notes take its organizer and anyone invited, unless it was canceled or resolved async. Notes already there word for word aren't added twice. Nobody is notified.

| Input | Type | Required | Description |
|---|---|---|---|
| `meeting_id` | string | yes | The meeting's id, as list_meetings returns it (or search's meeting:<id>) (1–200 characters) |
| `notes` | string | yes | The notes to add, at most 5,000 characters; they go after any notes already there (1–5000 characters) |
| `agenda_item` | string | no | The agenda item they are about: its id from get_meeting, or its exact title. Left out, they go on the meeting's own notes (1–200 characters) |
| `source_app` | string | no | The app they came from (Granola, Fireflies, Otter, Fathom…), named on their first line; the assistant's own name when left out (1–60 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |

<a id="tool-set-transcript-speakers"></a>
### Set transcript speakers

`set_transcript_speakers` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** Write connections only

Says who the speakers in one of a meeting's transcripts are, as the Transcript tab's speaker confirmation does in GPS: each speaker, as the transcript names them, given a person in the organization, or nobody. Speakers not named keep who GPS has them as. Anyone who can see the meeting may. Nothing is taken from the transcript: what it proposes (actions, decisions, a summary) a person asks for and decides in GPS. Sending the same people again changes nothing.

| Input | Type | Required | Description |
|---|---|---|---|
| `meeting_id` | string | yes | The meeting's id, as list_meetings returns it (or search's meeting:<id>) (1–200 characters) |
| `transcript_id` | string | no | Which transcript, from get_meeting_transcript; the meeting's newest when left out (1–200 characters) |
| `speakers` | array of object | yes | Who each of these speakers is; any speaker not named keeps who GPS has them as (1–100 items) |
| `speakers[].speaker` | string | yes | A speaker, named as the transcript names them (1–120 characters) |
| `speakers[].person` | string or null | yes | Who they are in the organization: 'me', a name, email or id; null for nobody (a guest, say) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |

<a id="your-check-ins"></a>
## Your check-ins

Answering your own check-ins: a meeting's, before or after it, and one a consultant sent you through myPortal.

<a id="tool-get-my-meeting-checkin"></a>
### Get my check-in for a meeting

`get_my_meeting_checkin` · **read** · Read-only

**Who sees it:** Everyone

The connected person's own check-in for one meeting, as its Hub shows it: the check-in before it (pre) or the check-out after it (post), what it asks, who will read the answers, what they have saved so far, whether it is sent, and whether it can still be changed and why not. It names their own objectives the meeting is about, each with its kind, units, figure and target, since a value sent for one moves the objective; the open actions they took away from the last meeting; and, after it, their commitments from it and its decisions. Only people the meeting invites check in. Titles and answers quote what people wrote.

| Input | Type | Required | Description |
|---|---|---|---|
| `meeting_id` | string | yes | The meeting's id, as list_meetings and get_my_focus give it (or search's meeting:<id>) (1–200 characters) |
| `phase` | one of `pre`, `post` | no | pre or post; left out, the one open now: the check-out once the meeting has been held, else the check-in before it |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |

<a id="tool-get-my-checkin"></a>
### Get a check-in I've been sent

`get_my_checkin` · **read** · Read-only

**Who sees it:** Everyone

One check-in a consultant sent the connected person through myPortal, as myHub shows it to them: each question (its type, whether it is required, its options or scale, and what an answer takes), what they have saved for each, how many are answered and which required ones are not, whether it is sent, and when it closes. Only their own answers, and only a check-in they were asked to answer. Questions are written by the consultant; answers quote what the person wrote.

| Input | Type | Required | Description |
|---|---|---|---|
| `checkin_id` | string | yes | The check-in's id, as get_my_focus lists it under open_checkins (1–200 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |

<a id="tool-answer-meeting-checkin"></a>
### Answer my check-in for a meeting

`answer_meeting_checkin` · **write** · Changes GPS · Can't be undone by the assistant · Emails people

**Who sees it:** Write connections only

Saves the connected person's own check-in for a meeting they are invited to: the check-in before it (pre: pulse, headlines, blockers, topics, their objectives on it, the actions they took away last time) or the check-out after it (post: a rating, their commitments from it, its decisions). submit false saves a draft and changes nothing else; answers given replace those saved, and answers left out are kept. submit true sends it, exactly as sending it in GPS does: each objective value goes onto the objective as a check-in, in the objective's own units (value_kind must be its kind), each action is marked, a rating lands on the meeting, and a commitment flagged or given a different date tells the organizer at once, in GPS and by email where they take those. A send names who it was told would read the answers (expected_visibility). Refused once the check-in has locked (the meeting started after it was sent, ended, or was canceled). Answers with what moved, before and after.

| Input | Type | Required | Description |
|---|---|---|---|
| `meeting_id` | string | yes | The meeting's id, as list_meetings and get_my_focus give it (or search's meeting:<id>) (1–200 characters) |
| `phase` | one of `pre`, `post` | yes | pre: the check-in before the meeting; post: the check-out after it |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `submit` | boolean | yes | false saves a draft, changing nothing else; true sends it, which applies it as described |
| `expected_visibility` | one of `hidden_until_start`, `attendees`, `organiser` | no | Required with submit: who reads the answers, as get_my_meeting_checkin's who_reads_answers.visibility said |
| `rsvp` | one of `attending`, `late`, `absent` or null | no | Whether the person is coming: attending, late or absent |
| `pulse` | object or null | no | Before: how they're going, 1 to 5, with an optional note; null takes it out |
| `pulse.score` | integer | yes | (1–5) |
| `pulse.note` | string | no | (1–280 characters) |
| `headlines` | array of object | no | Before: good or bad news the team should hear. Replaces the headlines saved before; [] clears them (at most 20 items) |
| `headlines[].tone` | one of `good`, `bad` | yes |  |
| `headlines[].text` | string | yes | (1–280 characters) |
| `blockers` | array of string | no | Before: what's blocking them. Replaces those saved before (at most 20 items) |
| `topics` | array of string | no | Before: topics they'd like to raise. Replaces those saved before (at most 20 items) |
| `objectives` | array of object | no | Before: their objectives on this meeting, each by id. Each one given replaces that objective's answer; the rest are kept (at most 20 items) |
| `objectives[].objective` | string | yes | The objective's id, as get_my_meeting_checkin lists it (1–64 characters) |
| `objectives[].value` | number or null | no | Its figure now, as a plain number in its own units (82000, not '$82k'), which sending writes onto the objective; null takes a saved value out |
| `objectives[].value_kind` | one of `number`, `currency`, `percentage`, `status` | no | With value: what kind of figure it is (currency, percentage, number or status), which must be the objective's own kind |
| `objectives[].status` | one of `complete`, `not_complete` | no | For a status objective, in place of value |
| `objectives[].comment` | string or null | no | What's behind it, kept on the check-in for the room to read; null takes it out |
| `actions` | array of object | no | Before: what became of the actions they took away last time (done, not_done or blocked), each by id (at most 20 items) |
| `actions[].action` | string | yes | The action's id, as get_my_meeting_checkin lists it (1–64 characters) |
| `actions[].state` | one of `done`, `not_done`, `blocked` | yes |  |
| `actions[].comment` | string or null | no |  |
| `rating` | object or null | no | After: how the meeting went, 1 to 5; null takes it out |
| `rating.score` | integer | yes | (1–5) |
| `rating.why` | string | no | (1–500 characters) |
| `commitments` | array of object | no | After: the actions they took away from this meeting, each by id (at most 20 items) |
| `commitments[].action` | string | yes | The action's id, as get_my_meeting_checkin lists it (1–64 characters) |
| `commitments[].response` | one of `accepted`, `changed`, `flagged` | yes | accepted: they'll do it; changed: they need a different date; flagged: it's in trouble |
| `commitments[].proposed_due_date` | string | no | With changed: the date they propose, YYYY-MM-DD. Proposed to the organizer, never set |
| `commitments[].comment` | string or null | no |  |
| `decisions` | array of object | no | After: whether each decision it recorded is what the room agreed (at most 20 items) |
| `decisions[].decision` | string | yes | The decision's id, as get_my_meeting_checkin lists it (1–64 characters) |
| `decisions[].agree` | boolean | yes |  |
| `decisions[].comment` | string or null | no |  |

<a id="tool-answer-checkin"></a>
### Answer a check-in I've been sent

`answer_checkin` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** Write connections only

Saves the connected person's own answers to a check-in their consultant sent them through myPortal, as answering it on myHub does: each answer by question (its id, or its number from 1), in the shape that question takes; answers left out keep what was saved. submit false saves a draft; submit true sends it to the consultant, and is refused while a required question is unanswered, naming each one. Only a check-in they were asked to answer, and only while it is open; a sent check-in can still be changed until it closes, and saving it as a draft again takes it back until it is sent again. Questions are written by the consultant.

| Input | Type | Required | Description |
|---|---|---|---|
| `checkin_id` | string | yes | The check-in's id, as get_my_focus lists it under open_checkins (1–200 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `answers` | array of object | no | The answers to save, by question. Each replaces that question's saved answer; questions left out keep theirs (at most 25 items) (default `[]`) |
| `answers[].question` | string or integer | yes | The question's id, or its number from 1, as get_my_checkin lists them |
| `answers[].value` | number or string or boolean or array of string or null | yes | The answer, in the shape the question takes (get_my_checkin's `takes`); null takes a saved answer out |
| `answers[].note` | string | no | A note, for a pulse or traffic-light question (at most 280 characters) |
| `submit` | boolean | yes | false saves a draft; true sends it to the consultant, which needs every required question answered |

<a id="people"></a>
## People

The team, the accountability chart (and changes to it), workload, and vision and values.

<a id="tool-list-people"></a>
### List people

`list_people` · **read** · Read-only

**Who sees it:** Everyone

Lists the people in a GPS organization that work can be assigned to, as GPS's people pickers offer them: each one's person_id, name, email, role, job title, whether they have accepted their invitation, and which one is the connected person. Sorted by name. Filter by part of a name or email with query, or by role. Names and job titles are written by people.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to read, as list_organizations gives it. Leave it out for the connection's default organization. |
| `query` | string | no | Part of a name or email, matched ignoring case. (at most 200 characters) |
| `role` | one of `Viewer`, `Team Member`, `Team Leader`, `Admin`, `Super Admin`, `Owner` | no | Only people with this role. |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-get-org-chart"></a>
### Get the accountability chart

`get_org_chart` · **read** · Read-only

**Who sees it:** Everyone

Returns an organization's accountability chart (org chart) from GPS, top down: each position's title, who it reports to, its department, employment type, location, whether it's vacant, and who holds it. GWC ratings appear where the chart is in accountability mode and GPS shows them to the caller. Narrow it to one person's positions and teams (person), one position's team (root_position), a department, or a number of levels (max_depth). detailed adds responsibilities, descriptions and each holder's member_id. Titles, names and descriptions are written by people.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to read, as list_organizations gives it. Leave it out for the connection's default organization. |
| `person` | string | no | Only the positions this person holds and the teams below them: their name, email, person_id, or 'me'. (1–200 characters) |
| `root_position` | string | no | Only this position and the team below it: its title or position_id. (1–200 characters) |
| `department` | string | no | Only positions in this department: its name or id. (1–200 characters) |
| `max_depth` | integer | no | How many levels to show, counting the first position shown as level 1. (1–10) |
| `include_unplaced` | boolean | no | Whether a whole-chart answer lists the people not yet placed on the chart (default true). (default `true`) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |

<a id="tool-get-workload"></a>
### Get workload

`get_workload` · **read** · Read-only

**Who sees it:** Everyone

Returns one organization's team workload in GPS: who has what in that organization. For the people on its accountability chart, each person's load level (light, balanced, heavy, overloaded) with GPS's reasons and counts of open, overdue and slipping actions and open and off-track objectives. Name a person to see their open actions and objectives too. Admins see everyone, a team leader their team, and anyone else their own, as in GPS. Dates are judged in the organization's time zone. Titles are written by people. A consultant's own hours across their client accounts are in get_consultant_capacity.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to read, as list_organizations gives it. Leave it out for the connection's default organization. |
| `person` | string | no | One person to show in full, with the actions and objectives behind their load: their name, email, person_id, or 'me'. Leave it out for everyone whose workload you may see. (1–200 characters) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |

<a id="tool-get-vision-and-values"></a>
### Get vision and values

`get_vision_and_values` · **read** · Read-only

**Who sees it:** Everyone

Returns an organization's vision statement and core values from GPS, and its Vision & Culture sections: purpose, differentiators, BHAG, the 1, 3, 5 and 10 year horizon map, strategic enablers and culture. The sections are included only for the roles GPS shows them to (admins and Team Members); anything not yet written is null or empty. All of it is written by people.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to read, as list_organizations gives it. Leave it out for the connection's default organization. |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |

<a id="tool-preview-org-chart-positions"></a>
### Preview adding positions to the org chart

`preview_org_chart_positions` · **preview** · Read-only · Previews `create_org_chart_positions`, changes nothing

**Who sees it:** Write connections only

Previews adding positions to the accountability chart (org chart) in Empiraa GPS without changing anything: one or more new positions under a position (by id or exact title) or at the top of the chart, each with its title, department, description, employment type, location, responsibilities, the people who hold it and the positions under it, up to 50 in all and 4 levels deep. Each person is a GPS person ('me', a name, an email or an id) or someone outside GPS by name, who goes on the chart by name only and is never invited. The preview shows every position as it would be made, which departments would be new, and warnings such as a position of the same title already there. Returns a preview_token that create_org_chart_positions applies once within 15 minutes, all together or not at all. Admins, Super Admins and Owners add anywhere; a Team Leader only under their own positions and their team. Titles and names are written by people.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `under` | string or null | yes | The position the new ones report to, by its id or exact title; null puts them at the top of the chart |
| `positions` | array of object | yes | The new positions, each with the positions under it (children), 50 in all at most and 4 levels deep (1–50 items) |
| `positions[].title` | string | yes | The position's title, as its box on the chart shows it (1–100 characters) |
| `positions[].department` | string | no | Its department, by name, matched ignoring case. A name that isn't a department yet is added for someone who manages the whole chart; a Team Leader's gets none (1–60 characters) |
| `positions[].description` | string | no | What the position is for (at most 2000 characters) |
| `positions[].employment_type` | one of `full-time`, `part-time`, `contractor`, `advisor` | no |  |
| `positions[].location` | string | no | (at most 80 characters) |
| `positions[].vacancy` | one of `open`, `hiring`, `planned` | no | For a position nobody holds: open (the default), hiring or planned |
| `positions[].assistant` | boolean | no | An assistant position (an executive assistant, a chief of staff), drawn beside its manager |
| `positions[].responsibilities` | array of string | no | What it is accountable for, in order (at most 20 items) |
| `positions[].people` | array of object | no | Who holds it, each a GPS person or an outside name; nobody leaves it vacant (at most 20 items) |
| `positions[].people[].person` | string | no | A GPS person: 'me', their name, email or person_id (1–200 characters) |
| `positions[].people[].outside_name` | string | no | Someone who isn't in GPS, by name: they go on the chart by name only, and aren't invited (1–100 characters) |
| `positions[].children` | array of object | no | Positions that report to it (at most 50 items) |
| `positions[].children[].title` | string | yes | The position's title, as its box on the chart shows it (1–100 characters) |
| `positions[].children[].department` | string | no | Its department, by name, matched ignoring case. A name that isn't a department yet is added for someone who manages the whole chart; a Team Leader's gets none (1–60 characters) |
| `positions[].children[].description` | string | no | What the position is for (at most 2000 characters) |
| `positions[].children[].employment_type` | one of `full-time`, `part-time`, `contractor`, `advisor` | no |  |
| `positions[].children[].location` | string | no | (at most 80 characters) |
| `positions[].children[].vacancy` | one of `open`, `hiring`, `planned` | no | For a position nobody holds: open (the default), hiring or planned |
| `positions[].children[].assistant` | boolean | no | An assistant position (an executive assistant, a chief of staff), drawn beside its manager |
| `positions[].children[].responsibilities` | array of string | no | What it is accountable for, in order (at most 20 items) |
| `positions[].children[].people` | array of object | no | Who holds it, each a GPS person or an outside name; nobody leaves it vacant (at most 20 items) |
| `positions[].children[].people[].person` | string | no | A GPS person: 'me', their name, email or person_id (1–200 characters) |
| `positions[].children[].people[].outside_name` | string | no | Someone who isn't in GPS, by name: they go on the chart by name only, and aren't invited (1–100 characters) |
| `positions[].children[].children` | array of object | no | Positions that report to it (at most 50 items) |
| `positions[].children[].children[].title` | string | yes | The position's title, as its box on the chart shows it (1–100 characters) |
| `positions[].children[].children[].department` | string | no | Its department, by name, matched ignoring case. A name that isn't a department yet is added for someone who manages the whole chart; a Team Leader's gets none (1–60 characters) |
| `positions[].children[].children[].description` | string | no | What the position is for (at most 2000 characters) |
| `positions[].children[].children[].employment_type` | one of `full-time`, `part-time`, `contractor`, `advisor` | no |  |
| `positions[].children[].children[].location` | string | no | (at most 80 characters) |
| `positions[].children[].children[].vacancy` | one of `open`, `hiring`, `planned` | no | For a position nobody holds: open (the default), hiring or planned |
| `positions[].children[].children[].assistant` | boolean | no | An assistant position (an executive assistant, a chief of staff), drawn beside its manager |
| `positions[].children[].children[].responsibilities` | array of string | no | What it is accountable for, in order (at most 20 items) |
| `positions[].children[].children[].people` | array of object | no | Who holds it, each a GPS person or an outside name; nobody leaves it vacant (at most 20 items) |
| `positions[].children[].children[].children` | array of object | no | Positions that report to it (at most 50 items) |

<a id="tool-create-org-chart-positions"></a>
### Add previewed positions to the org chart

`create_org_chart_positions` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** Write connections only

Adds to the accountability chart (org chart) in Empiraa GPS the positions a preview_org_chart_positions preview showed, from its preview_token: the whole tree in one change, with the people, departments and responsibilities it showed, or nothing at all. If the position they go under has changed since the preview, or so have this person's rights there, nothing is added and what changed is listed. People outside GPS go on by name only; nobody is invited or emailed. A preview is applied once. Returns each position added, with its id.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `preview_token` | string | yes | The preview_token preview_org_chart_positions returned |

<a id="tool-update-position"></a>
### Update an org chart position

`update_position` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** Write connections only

Changes a position on the accountability chart (org chart) in Empiraa GPS, by its id or exact title: its title, description, department (by name or id; a new name is added for someone who manages the whole chart), employment type, location, vacancy, whether it is an assistant, its responsibilities (replaced as a list), who it reports to (its team moves with it) and its place among its manager's reports. Everything asked for is made together, or nothing is; the answer lists what changed, before and after, and a request that changes nothing writes nothing. Admins, Super Admins and Owners change any position; a Team Leader only the positions below their own. Titles and text are written by people.

| Input | Type | Required | Description |
|---|---|---|---|
| `position` | string | yes | The position, by its id or exact title (1–300 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `title` | string | no | A new title (1–100 characters) |
| `description` | string or null | no | A new description; null or empty clears it |
| `department` | string or null | no | Its department, by name or id; null takes it off. A name that isn't a department yet is added for someone who manages the whole chart |
| `employment_type` | one of `full-time`, `part-time`, `contractor`, `advisor` or null | no | null clears it |
| `location` | string or null | no | null or empty clears it |
| `vacancy` | one of `open`, `hiring`, `planned` | no | For a position nobody holds: open, hiring or planned |
| `assistant` | boolean | no | Whether it is an assistant position, drawn beside its manager |
| `responsibilities` | array of string | no | Replaces its responsibilities, in order; an empty list clears them (at most 20 items) |
| `reports_to` | string or null | no | The position it reports to, by id or exact title; null puts it at the top of the chart. Its team moves with it |
| `index` | integer | no | Its place among its manager's reports, from 0; left out, it goes last under a new manager and stays put under the same one (0–500) |

<a id="tool-assign-person-to-position"></a>
### Put someone in an org chart position

`assign_person_to_position` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** Write connections only

Puts someone in a position on the accountability chart (org chart) in Empiraa GPS, by the position's id or exact title: a GPS person ('me', a name, an email or an id), or someone outside GPS by name (outside_name), who goes on the chart by name only. It never invites anyone to GPS, emails anyone or gives anyone a seat. The first person in a vacant position fills it; others are added after those already there. Admins, Super Admins and Owners change any position; a Team Leader only the positions below their own. Names are written by people.

| Input | Type | Required | Description |
|---|---|---|---|
| `position` | string | yes | The position, by its id or exact title (1–300 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `person` | string | no | A GPS person: 'me', their name, email or person_id (1–200 characters) |
| `outside_name` | string | no | Someone who isn't in GPS, by name: they go on the chart by name only, and aren't invited (1–100 characters) |

<a id="tool-unassign-person-from-position"></a>
### Take someone out of an org chart position

`unassign_person_from_position` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** Write connections only

Takes someone out of a position on the accountability chart (org chart) in Empiraa GPS, by the position's id or exact title and one of: the GPS person ('me', a name, an email or an id), the name of someone outside GPS as the chart shows it, or their member_id from get_org_chart. The person stays in GPS and the position stays on the chart; the last person out leaves it vacant (open). Admins, Super Admins and Owners change any position; a Team Leader only the positions below their own. Names are written by people.

| Input | Type | Required | Description |
|---|---|---|---|
| `position` | string | yes | The position, by its id or exact title (1–300 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `person` | string | no | A GPS person in it: 'me', their name, email or person_id (1–200 characters) |
| `outside_name` | string | no | Someone outside GPS in it, by the name the chart shows (1–100 characters) |
| `member_id` | string | no | Their member_id, as get_org_chart shows it in detail (1–100 characters) |

<a id="tool-remove-empty-position"></a>
### Remove an empty org chart position

`remove_empty_position` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** Write connections only

Removes one position from the accountability chart (org chart) in Empiraa GPS, by its id or exact title, only while it is empty: nobody holds it and no position reports to it. A position someone holds, or with anything under it, is refused with the reason, and nothing else is ever removed. Its dotted lines go with it. The change can be undone in GPS, which puts the position back with its details and dotted lines. Admins, Super Admins and Owners remove any empty position; a Team Leader only one below their own. Titles are written by people.

| Input | Type | Required | Description |
|---|---|---|---|
| `position` | string | yes | The position, by its id or exact title (1–300 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |

<a id="tool-update-vision-and-culture"></a>
### Update Vision & Culture

`update_vision_and_culture` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** Write connections only

Writes an organization's vision statement, its core values and its Vision & Culture sections in Empiraa GPS: purpose, BHAG (and the line under it), the 1, 3, 5 and 10 year horizon map, why we're different, the strategic enablers and culture. Each section given replaces what it says (the core values as one list); the horizons change one by one, so a horizon left out stays as it is. Only what differs is written, a request that changes nothing writes nothing, and the answer lists each change, before and after; the change can be undone in GPS. Admins, Super Admins and Owners can make it. All of it is written by people.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `vision` | string or null | no | The vision statement, shown on the Strategy One Pager; null or empty clears it |
| `purpose_statement` | string or null | no | Our Purpose: why the organization exists; null or empty clears it |
| `bhag_headline` | string or null | no | Our BHAG: the Big Hairy Audacious Goal; null or empty clears it |
| `bhag_subtext` | string or null | no | A line under the BHAG (by when, how it's measured); null or empty clears it |
| `horizon` | array of object | no | Where We Want To Be: the 1, 3, 5 and 10 year horizon map. Only the horizons given change; the others stay as they are (1–4 items) |
| `horizon[].years` | one of `1`, `3`, `5`, `10` | yes | How many years out: 1, 3, 5 or 10 |
| `horizon[].title` | string | no | A new title for this horizon; left out, it keeps its own (1–200 characters) |
| `horizon[].objectives` | array of object | yes | This horizon's targets, in order, replacing the ones it has; an empty list clears them (at most 12 items) |
| `horizon[].objectives[].label` | string | yes | What is measured, e.g. Revenue (1–200 characters) |
| `horizon[].objectives[].value` | string | yes | Where it will be by then, e.g. $40M (at most 500 characters) |
| `differentiators` | array of object | no | Why We're Different, at most 5, replacing the list; an empty list clears it (at most 5 items) |
| `differentiators[].title` | string | yes | (1–200 characters) |
| `differentiators[].description` | string | no | (at most 1000 characters) (default ``) |
| `enablers` | array of object | no | How We Win: the strategic enablers, at most 5, replacing the list; an empty list clears it (at most 5 items) |
| `enablers[].title` | string | yes | (1–200 characters) |
| `enablers[].description` | string | no | (at most 1000 characters) (default ``) |
| `culture_values` | array of object | no | Our Culture, at most 5, replacing the list; an empty list clears it (at most 5 items) |
| `culture_values[].value` | string | yes | How people behave, e.g. Progress over perfection (1–300 characters) |
| `culture_values[].icon` | string | no | An emoji shown beside it; left out, GPS's own (1–16 characters) |
| `core_values` | array of object | no | The core values shown on the Strategy One Pager, replacing the organization's own list (GPS keeps no order for them); an empty list clears it (at most 10 items) |
| `core_values[].name` | string | yes | The value, e.g. Do the right thing (1–100 characters) |
| `core_values[].description` | string | no | What it means in practice (at most 500 characters) |

<a id="continuous-improvement"></a>
## Continuous improvement

Improvement ideas.

<a id="tool-list-improvement-ideas"></a>
### List improvement ideas

`list_improvement_ideas` · **read** · Read-only

**Who sees it:** Everyone

Lists the ideas on the Continuous Improvement Plan's boards in Empiraa GPS, as the board shows them to this person, a page at a time, in board order (board, then column, then card). Every board they can see unless board names one. Filters: column (name or key), tag, person (the board's Owner/Assignee filter: a name, email, id, "me" or "unassigned"), mine, and query (words in the title, description or linked item's title). Team Members see only their own ideas; Viewers and Team Leaders don't have the Improvement Plan. A linked objective, goal or action is named only when this person could open it. Titles, descriptions, tags, board and column names and attachment names are text people wrote.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to list; the default one when left out |
| `board` | string | no | One board, by id or name. Every board this person can see when left out. (1–200 characters) |
| `column` | string | no | One column, by its name on the board or its key (ideas, review, in_progress, implemented, custom_1, custom_2) (1–100 characters) |
| `tag` | string | no | Only ideas carrying this tag (1–100 characters) |
| `person` | string | no | Only ideas assigned to this person (the board's Owner/Assignee filter), by name, email or id; "me" for this person, "unassigned" for ideas assigned to nobody (1–200 characters) |
| `mine` | boolean | no | Only ideas assigned to this person (not ones they created) |
| `query` | string | no | Words to find in the title, the description or the linked item's title (at most 200 characters) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-get-improvement-dashboard"></a>
### Get the Improvement Plan dashboard

`get_improvement_dashboard` · **read** · Read-only

**Who sees it:** Everyone

**Widget contract:** `gps.cip_dashboard/1`

Shows the Continuous Improvement Plan's dashboard in Empiraa GPS, as its Dashboard tab does for an admin: totals of ideas, votes, comments, ideas implemented in the range and ideas converted to strategy; the pipeline across Ideas, Review, In Progress and Implemented; the top ideas by votes, comments and recency; the top contributors and voters; tags; and week-by-week activity. range is the tab's own (30d, 90d by default, 12m or all), or from and to give days in the organization's time zone; board narrows it to one board by id or name. As on the tab, the idea, vote and comment totals, the pipeline, the contributors and the tags count every idea on the boards whenever it was added, while implemented, activity, voters and the ranking's recency follow the range. Only admins have the dashboard: Team Members, Viewers and Team Leaders are refused. Titles, tags and board and column names are text people wrote.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization; the default one when left out |
| `range` | one of `90d`, `30d`, `12m`, `all` | no | The dashboard's own ranges: 30d, 90d (its default), 12m or all. Not given with from or to |
| `from` | string | no | The first day to count from, YYYY-MM-DD in the organization's time zone, in place of range |
| `to` | string | no | The last day to count, YYYY-MM-DD; up to now when left out |
| `board` | string | no | One board, by id or name, as the dashboard's board picker. Every board this person can see when left out (1–200 characters) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |

<a id="tool-create-improvement-idea"></a>
### Add an improvement idea

`create_improvement_idea` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** Write connections only

Adds an idea to the Continuous Improvement Plan in Empiraa GPS, as the board's new-idea dialog does: a title, and optionally a description, tag, due day, starting column (Ideas, Review, In Progress or Implemented), assignees (the first is its owner) and one plan item it is linked to (link_objective, link_goal or link_action). It goes on the board named, else on the first board this person can see. A Team Member who assigns nobody owns the idea, so their board keeps showing it. Viewers and Team Leaders don't have the Improvement Plan, and someone with no seat in the organization can't add ideas. Titles, descriptions, tags and names are text people wrote.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `title` | string | yes | The idea, as its card shows it (1–200 characters) |
| `description` | string | no | More about the idea (at most 5000 characters) |
| `board` | string | no | The board, by id or exact name; the first board this person can see when left out (1–300 characters) |
| `column` | string | no | Where it starts: Ideas, Review, In Progress or Implemented, by name or key (ideas, review, in_progress, implemented). Ideas when left out (1–60 characters) |
| `tag` | string | no | A tag, as the board's tag filter shows it (at most 40 characters) |
| `due_date` | string | no | When it is due, YYYY-MM-DD |
| `assignees` | array of string | no | Who it is assigned to ('me', names, emails or ids); the first is its owner. Nobody when left out, except that a Team Member owns the ideas they add (at most 50 items) |
| `link_objective` | string | no | An objective it is linked to, by id or exact title (1–300 characters) |
| `link_goal` | string | no | A goal it is linked to, by id or exact title (1–300 characters) |
| `link_action` | string | no | An action it is linked to, by id or exact title (1–300 characters) |

<a id="tool-update-improvement-idea"></a>
### Update an improvement idea

`update_improvement_idea` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** Write connections only

Changes an idea on the Continuous Improvement Plan in Empiraa GPS that this person's board shows them: its title, description, tag or due day; its column (by name or key, the board's own columns included); its assignees (replace them, or add and remove some); or the plan item it is linked to (link_objective, link_goal or link_action, or unlink). Each part is written as GPS writes it, and the answer lists what changed, before and after, and how each part went; a request that changes nothing writes nothing. Viewers and Team Leaders don't have the Improvement Plan, and a Team Member changes only the ideas their board shows them. Titles, descriptions, tags and names are text people wrote.

| Input | Type | Required | Description |
|---|---|---|---|
| `idea` | string | yes | The idea, by id or exact title (1–300 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `title` | string | no | A new title (1–200 characters) |
| `description` | string or null | no | A new description; null clears it |
| `tag` | string or null | no | A new tag; null clears it |
| `due_date` | string or null | no | A new due day, YYYY-MM-DD; null clears it |
| `column` | string | no | The column to move it to, by its name on the idea's board or its key (custom_1 and custom_2 too); it goes to the bottom (1–60 characters) |
| `assignees` | array of string | no | Replaces the assignees with exactly these people ('me', names, emails or ids) (at most 50 items) |
| `add_assignees` | array of string | no | People to add to the assignees, keeping the rest (at most 50 items) |
| `remove_assignees` | array of string | no | People to take off the assignees, keeping the rest (at most 50 items) |
| `link_objective` | string | no | Link it to this objective instead, by id or exact title (1–300 characters) |
| `link_goal` | string | no | Link it to this goal instead, by id or exact title (1–300 characters) |
| `link_action` | string | no | Link it to this action instead, by id or exact title (1–300 characters) |
| `unlink` | boolean | no | True takes its link off |

<a id="tool-vote-improvement-idea"></a>
### Vote for an improvement idea

`vote_improvement_idea` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** Write connections only

Votes for an idea on the Continuous Improvement Plan in Empiraa GPS, or takes this person's vote back (voted false), as the vote button on the idea's card does. Only an idea this person's board shows them can be voted on, and a vote that already stands as asked changes nothing. The answer is the idea with its vote count and whether this person has voted for it. Viewers and Team Leaders don't have the Improvement Plan, and someone with no seat in the organization can't vote. Titles, descriptions, tags and names are text people wrote.

| Input | Type | Required | Description |
|---|---|---|---|
| `idea` | string | yes | The idea, by id or exact title (1–300 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `voted` | boolean | yes | true votes for it; false takes this person's vote back |

<a id="notifications-files-and-reports"></a>
## Notifications, files and reports

What GPS has told the person, the files they can see, and saved reports.

<a id="tool-list-notifications"></a>
### List notifications

`list_notifications` · **read** · Read-only

**Who sees it:** Everyone

Lists the connected person's own GPS notifications in one organization, newest first, as their inbox shows them: what each is about, when it was sent, whether it has been read, where its button goes (open_url) and a link to it in the inbox. status picks the inbox tab (all, unread or archived); category narrows to meetings, plan, system or other; since to recent ones. Also returns the unread count. Reading here never marks anything read. Titles and bodies quote text people wrote.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to read, as list_organizations gives it. Leave it out for the connection's default organization. |
| `status` | one of `all`, `unread`, `archived` | no | The inbox tab: all (the default: everything not archived), unread (not archived and not yet read) or archived. (default `all`) |
| `category` | one of `meetings`, `plan`, `system`, `other` | no | Only one kind: meetings, plan (objectives, actions, check-ins, mentions), system, or other (any type none of those tabs claims). |
| `since` | string | no | Only notifications sent at or after this moment: an ISO 8601 date-time, or a date (YYYY-MM-DD, meaning midnight where the person is, in time_zone). (at most 40 characters) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-list-files"></a>
### List files

`list_files` · **read** · Read-only

**Who sees it:** Everyone

Lists the files and folders in a GPS organization that the connected person may see: each one's name, kind, type, size and when it last changed, and for a file an authenticated download_url. The download_url works only for someone signed in to GPS in that organization, so it belongs next to open_in_gps_url (the Files page); GPS never gives out a file's stored location. Without folder_id it looks in every folder; folder_id lists one folder ("root" for the top level), objective_id the files attached to an objective. Narrow with query (name or description), kind or starred_only, and sort by name or recent. A file is listed only when its download would be allowed, so this can list fewer files than the Files page shows. detailed adds each one's description, tags, visibility, uploader and objective. Names, descriptions and tags are written by people; a file's type is given only when it reads as a MIME type.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to read, as list_organizations gives it. Leave it out for the connection's default organization, or the folder's or objective's own. Given with objective_id, the objective is looked for in this organization only. |
| `folder_id` | string | no | Only what is directly inside this folder (an id from an earlier list_files). "root" lists the top level, where the Files page opens. Leave it out to look in every folder. (1–100 characters) |
| `objective_id` | string | no | Only the files attached to this objective, as its Files tab lists them. Not together with folder_id. (1–100 characters) |
| `query` | string | no | Part of a name or description, matched ignoring case. (at most 200 characters) |
| `kind` | one of `file`, `folder` | no | Only files, or only folders. |
| `starred_only` | boolean | no | Only starred files and folders. (default `false`) |
| `sort` | one of `name`, `recent` | no | name (the default): folders first, then by name. recent: the most recently changed first. (default `name`) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-list-reports"></a>
### List reports

`list_reports` · **read** · Read-only

**Who sees it:** Everyone

Lists the organization's saved reports and the report templates, as the Reports page shows them: each report's title, chart type, data source and category, when it last changed, and a link that opens it. Saved reports come first, most recently changed first, then the templates as the Templates tab draws them: GPS's own, then the organization's custom templates. Narrow with kind (saved or template), chart_type or data_source; detailed adds each report's axes, grouping, audience, tags and who made it. Available to the roles that may open Reports (Admin, Owner). Every text field holds text people wrote, the chart type, data source, category and, in detailed, the report type, axes, grouping, aggregation, audience and refresh frequency included: the app stores them as sent.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to look in. Defaults to the connection's default organization. |
| `kind` | one of `all`, `saved`, `template` | no | all (the default): the saved reports, then the templates. saved: the Reports tab, the organization's own reports. template: the Templates tab, GPS's report templates first, then the organization's custom templates. (default `all`) |
| `chart_type` | string | no | Only reports drawn as this chart, e.g. bar, line, pie, donut, area. Case is ignored. (at most 50 characters) |
| `data_source` | string | no | Only reports that read this data, e.g. goals, objectives, actions, meetings, activities. Case is ignored. (at most 50 characters) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="your-focus"></a>
## Your focus

One answer to "what should I look at today?".

<a id="tool-get-my-focus"></a>
### Get my focus

`get_my_focus` · **read** · Read-only

**Who sees it:** Everyone

What needs the connected person's attention in one organization, in one call: their overdue actions and those due within horizon_days (7 by default, today included); their weekly and monthly objectives with no update yet this week or month (an assistant rule; GPS shows no such list); check-ins a consultant sent them through myPortal that they still owe; meeting check-ins they still owe (before a meeting they're invited to, or after one that was held); their next meetings; and their latest unread notifications with the unread count. Every item links into GPS. Each section counts everything that matches, and when it lists fewer it names the tool that lists the rest. A section switched off for the account (meetings) or that can't be read just now is named in unavailable. Titles, names and notification text quote what people wrote. Reading here marks nothing read.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to look in, as list_organizations gives it. Leave it out for the connection's default organization. |
| `horizon_days` | integer | no | How far ahead due_soon looks: today and the next horizon_days - 1 days, 1 to 14 (default 7: the week the Actions board calls "this week"). (1–14) (default `7`) |
| `limit` | integer | no | The most items each section lists, 1 to 25 (default 10). Meetings list at most 4 and notifications at most 5. (1–25) (default `10`) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |

<a id="myportal-client-accounts"></a>
## myPortal: client accounts

For consultants who run client accounts in myPortal. Nobody else is shown these tools.

<a id="tool-list-client-accounts"></a>
### List client accounts

`list_client_accounts` · **read** · Read-only

**Who sees it:** myPortal consultants only

**Widget contract:** `gps.client_health/1`

Lists the signed-in consultant's own client book: the client accounts you hold in myPortal, so no profile lookup is needed first. A page at a time, as the Overview's portfolio scores them: engagement band and score, delivery, why each isn't green, its consultant, its next meeting, the client's switch for assistants (full or view only) and what its admins let assistants do, and whether you hold a seat there. Unlike the Overview it lists every client you hold, seated or not. Worst first by default; filter by needs_attention, band, consultant or search. Detailed adds each account's type and this period's hours, which count all time logged on the account, by anyone. Accounts whose admins switched assistants off are counted, never named. Health is last night's. Contract gps.client_health/1.

| Input | Type | Required | Description |
|---|---|---|---|
| `needs_attention` | boolean | no | Only accounts whose engagement is red or orange |
| `band` | one of `green`, `orange`, `red`, `blue` | no | Only accounts in this engagement band; blue (too early to say) includes accounts not scored yet |
| `consultant` | string | no | Only accounts with this consultant: their name as listed, or "unassigned" (1–200 characters) |
| `search` | string | no | Only accounts whose name contains this (1–100 characters) |
| `sort` | one of `need`, `name`, `next_meeting` | no | need (the default): red first, then orange, too early to say, green, the lowest score first within a band; name; or next_meeting, soonest first (default `need`) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-get-client-account"></a>
### Get a client account

`get_client_account` · **read** · Read-only

**Who sees it:** myPortal consultants only

Returns one client account as myPortal's drill-down shows it: engagement health scored now, with its concerns and nightly trend; the plan's objective counts and progress; upcoming and recent meetings; open and overdue actions; how many people use it; this period's hours, which count all time logged on the account, by anyone; its type, modules and consultant; and what its admins let assistants do. The card note, industry and tags can be edited by the client's admins. No email address is shown. Without a seat there, goals aren't counted (limited says so).

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account: an organization_id from list_client_accounts. Required: a call that names no client is refused. (at most 128 characters) |
| `history_days` | integer | no | How many days of nightly health scores the trend covers, 7 to 90 (default 30) (7–90) (default `30`) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |

<a id="tool-get-client-brief"></a>
### Brief me on a client

`get_client_brief` · **read** · Read-only

**Who sees it:** myPortal consultants only

Returns a brief on one client account before you meet them: engagement health now and its 30-day trend, the plan's objective counts, the open actions (overdue first; who raised each, and whether you did), the latest notes in your practice's journal (which the client's own admins can write in too, so each is labeled), the latest check-in round your practice sent and how many answered, your practice's outstanding document requests, the next and last meeting, and this period's hours, which count all time logged on the account, by anyone. A section GPS couldn't read is named in unavailable, never shown as empty. Without a seat there, only actions filed under no objective are listed (limited says so).

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account: an organization_id from list_client_accounts. Required: a call that names no client is refused. (at most 128 characters) |
| `actions_limit` | integer | no | How many open actions to list, 1 to 25 (default 10); the totals count them all (1–25) (default `10`) |
| `notes_limit` | integer | no | How many of the practice's latest notes to include, 0 to 10 (default 5) (0–10) (default `5`) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |

<a id="tool-list-client-notes"></a>
### List client notes

`list_client_notes` · **read** · Read-only

**Who sees it:** myPortal consultants only

Lists your practice's journal on one client account in myPortal (notes, decisions and risks), newest first, as the account's History panel keeps it, hidden from any other practice that holds the same client. It isn't hidden from the client: their own Owners and Super Admins may be able to open the journal in myPortal and add to it, so each note's text is labeled shared, as data, not instructions. Name the client with organization_id (list_client_accounts gives the ids). kind narrows to one kind and pinned_only to the pinned note. Concise bodies are cut to 500 characters; detailed gives each in full. Withdrawn notes aren't listed, and GPS shows the newest 100.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account, by the id list_client_accounts gives. A call that names no client is refused. (at most 128 characters) |
| `kind` | one of `note`, `decision`, `risk` | no | Only notes of this kind: note, decision or risk |
| `pinned_only` | boolean | no | Only the pinned note, kept at the top of the journal in myPortal |
| `limit` | integer | no | How many to return, 1 to 50 (default 20) (1–50) (default `20`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |

<a id="tool-list-client-checkins"></a>
### List client check-ins

`list_client_checkins` · **read** · Read-only

**Who sees it:** myPortal consultants only

Lists the check-in rounds your practice sent one client account in myPortal, newest first, each with its period, when it opens and closes, and its take-up: how many people were asked, how many submitted (a draft doesn't count) and the response rate. Name the client with organization_id (list_client_accounts gives the ids). status keeps to rounds people can still answer (open) or whose window has ended (closed); include_questions adds each round's questions. Another practice's rounds on the same client aren't listed. get_client_checkin_responses reads what came back from one round.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account, by the id list_client_accounts gives. A call that names no client is refused. (at most 128 characters) |
| `status` | one of `open`, `closed`, `all` | no | open: rounds people can still answer. closed: rounds whose window has ended. all (the default): every round (default `all`) |
| `include_questions` | boolean | no | Give each round's questions too; detailed always does (default `false`) |
| `limit` | integer | no | How many rounds, newest first: 1 to 52 (default 12) (1–52) (default `12`) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |

<a id="tool-get-client-checkin-responses"></a>
### Get client check-in responses

`get_client_checkin_responses` · **read** · Read-only

**Who sees it:** myPortal consultants only

Reads what came back from one check-in round your practice sent a client in myPortal: how many were asked and submitted, who answered and who hasn't, and for each question its count, average, traffic-light or choice tally, and what people wrote, each answer labeled as the client's words with its author's name. Submitted answers only: a draft is never shown. Name the round with checkin_id (list_client_checkins gives the ids). include_names false leaves every name out, and max_answer_chars cuts long answers. Where the client's organization, or GPS itself, lets assistants see counts only, the answer gives how many answered and who, and nothing anyone wrote. A round still open gives partial results. Another practice's rounds aren't available here.

| Input | Type | Required | Description |
|---|---|---|---|
| `checkin_id` | string | yes | The round, by the id list_client_checkins gives (1–64 characters) |
| `organization_id` | string | no | The client account; the round names it, so this is only checked against it (at most 128 characters) |
| `include_names` | boolean | no | Name who answered and who hasn't, as myPortal does (the default); false gives counts only (default `true`) |
| `max_answer_chars` | integer | no | The most characters of each written answer, 200 to 4,000 (default 1,000) (200–4000) (default `1000`) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |

<a id="tool-list-document-requests"></a>
### List document requests

`list_document_requests` · **read** · Read-only

**Who sees it:** myPortal consultants only

Lists the document requests your practice has raised with clients in your myPortal book, as myPortal's Documents panel shows them: what was asked for and who was asked, when each is due, how far along it is, and what is still to come. client narrows to one account (an id from list_client_accounts, or its exact name); status and overdue_only narrow further. Only your practice's requests are listed, never another practice's on a client you share, and clients whose assistants are switched off are left out. Overdue means past the due date in the client's own calendar. detailed adds each document with its status, any note on it, and the uploaded file's name, type and size; files themselves are never linked. Says whether GPS reminds people automatically here.

| Input | Type | Required | Description |
|---|---|---|---|
| `client` | string | no | One client account: an organization id from list_client_accounts, or the account's exact name. Every client in your book when left out (1–200 characters) |
| `status` | one of `outstanding`, `open`, `partial`, `draft`, `complete`, `cancelled` | no | outstanding (open or partly in), open, partial, draft (not sent yet), complete or `cancelled`. `complete` and `cancelled` include those however include_complete is set |
| `include_complete` | boolean | no | `complete` and `cancelled` requests too (left out by default) (default `false`) |
| `overdue_only` | boolean | no | Only requests past their due date in the client's own calendar and still waiting |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-list-strategy-templates"></a>
### List strategy templates

`list_strategy_templates` · **read** · Read-only

**Who sees it:** myPortal consultants only

Lists Empiraa's shipped strategy templates, the library a consultant applies to a client account's plan: each one's name, slug, category, description and how many goals and objectives it holds, a page at a time, in category order, with every category and how many templates it holds. Filter by category, or search for words in the name, slug, description or category. It reads no client account, so it takes no organization_id. To see what one would add to a client's plan, pass its slug to preview_strategy_template. A practice's own templates aren't listed: they are applied in myPortal.

| Input | Type | Required | Description |
|---|---|---|---|
| `category` | string | no | Only templates in this category, named as categories lists it (1–100 characters) |
| `search` | string | no | Only templates whose name, slug, description or category holds every word of this (1–100 characters) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-get-consultant-capacity"></a>
### Get consultant capacity

`get_consultant_capacity` · **read** · Read-only

**Who sees it:** myPortal consultants only

Shows the signed-in consultant's, and their myPortal practice's, hours against capacity across their client accounts, which answers 'am I over capacity'. Over the coming weeks, in hours: what is allocated to their client accounts plus the meetings scheduled for them, against their weekly capacity after leave, banded light, balanced, heavy or overloaded, with each one's worst week. Only your own practice's consultants on the accounts you hold. Hours only: no rates, costs, billable time or utilization. A consultant's totals cover every organization they work in. Name one consultant ('me', an id or a name) for just them; detailed adds the week-by-week figures and their leave periods. Who has what inside one organization is get_workload.

| Input | Type | Required | Description |
|---|---|---|---|
| `consultant` | string | no | One consultant: 'me', a consultant_id from an earlier answer, or their name. Leave it out for every consultant in your practice. (1–200 characters) |
| `weeks` | integer | no | How many weeks ahead, from this week, at most 12 (1–12) (default `12`) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |

<a id="tool-get-my-timesheet"></a>
### Get my timesheet

`get_my_timesheet` · **read** · Read-only

**Who sees it:** myPortal consultants only

Shows the signed-in consultant's own myPortal timesheet for one week (this week unless another is named): each client they logged time on, the hours on each day, the day and week totals, and where the week stands (not submitted, waiting on approval, approved, or sent back with the approver's reason), whether it can be submitted, and whether it is locked and why. A day that is exactly one entry gives that entry's id, which update_time_entry and void_time_entry take. Weeks run Monday to Sunday in the practice's time zone. Only your own week: get_practice_week shows everyone's. Hours only: no rates, costs or billing. Clients whose admins switched assistants off, or that aren't in your own book, are counted but never named.

| Input | Type | Required | Description |
|---|---|---|---|
| `week` | string | no | 'this', 'last', or any day in the week as YYYY-MM-DD; weeks run Monday to Sunday in your practice's time zone (1–10 characters) |

<a id="tool-get-practice-week"></a>
### Get the practice's week

`get_practice_week` · **read** · Read-only

**Who sees it:** myPortal consultants only

Shows everyone in the signed-in consultant's myPortal practice for one week (this week unless another is named): each person's hours on each day, their week's total, and where their timesheet stands (not submitted, waiting on approval, approved, or sent back), with the people who logged nothing at all named. A person's hours cover every client they work on; no client is named here. Weeks run Monday to Sunday in the practice's time zone. Only your own practice's people. Read only, and hours only: no rates, costs or billing. One person's own week by client is get_my_timesheet for you, or get_time_report for anyone.

| Input | Type | Required | Description |
|---|---|---|---|
| `week` | string | no | 'this', 'last', or any day in the week as YYYY-MM-DD; weeks run Monday to Sunday in your practice's time zone (1–10 characters) |

<a id="tool-list-timesheets-to-approve"></a>
### List timesheets to approve

`list_timesheets_to_approve` · **read** · Read-only

**Who sees it:** myPortal consultants only

Lists the myPortal timesheet weeks waiting on the signed-in consultant as an approver: each person's submitted week with when it was submitted and the hours it was submitted with, oldest first, then the weeks sent back that wait on their person. An approver is whoever holds the practice's subscription and anyone they name in myPortal's Time settings; anyone else is told they aren't one, with nothing listed. Never your own week: somebody else approves it. Only your own practice's people. Hours only: no rates, costs or billing. A week's split by client is in get_time_report, for that person and week; review_timesheet_week approves, returns or reopens one.

No inputs.

<a id="tool-get-time-report"></a>
### Get a time report

`get_time_report` · **read** · Read-only

**Who sees it:** myPortal consultants only

Reports the hours the signed-in consultant's myPortal practice logged over a month or a from–to range of up to a year (this month in the practice's time zone unless another is named), totaled and split by client and by person, which answers 'how many hours did we spend on a client in September'. Narrow it to one client (by id or name) and one person ('me', an id or a name); a person and one week gives the split by client of that person's timesheet. Detailed adds each entry: its day, client, person, hours, note, how it was logged, and its id, which update_time_entry and void_time_entry take for your own. Voided entries are left out. Only your own practice's people are named; hours on a client by another practice sharing it, and on clients switched off for assistants or outside your own book, are counted apart and never named. Hours only: no rates, costs, billing or CSV.

| Input | Type | Required | Description |
|---|---|---|---|
| `month` | string | no | A calendar month, YYYY-MM. Left out with no from and to, this month in your practice's time zone. |
| `from` | string | no | The first day, YYYY-MM-DD; given with to, at most a year apart |
| `to` | string | no | The last day, YYYY-MM-DD, inclusive |
| `client` | string | no | One client: its organization_id, or its name (1–200 characters) |
| `person` | string | no | One person: 'me', a consultant_id, or their name (1–200 characters) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |

<a id="tool-get-my-day"></a>
### Get my day

`get_my_day` · **read** · Read-only

**Who sees it:** myPortal consultants only

Shows the signed-in consultant's own myPortal day, as the header timer does: their running timer (which client, since when, for how long, and whether it looks left on), and today's time entries in the practice's time zone, newest first, each with its client, hours, note, kind of work (its category, and whether it is billable), what it was for on the client's plan, what came of it and what's next, and its start and end when it was timed. Totals for today, split billable and non-billable. Only your own day. Billable hours, never rates or money. Clients whose admins switched assistants off, or that aren't in your own book, are counted but never named. Each entry's id is what update_time_entry and void_time_entry take.

No inputs.

<a id="tool-list-time-allocation-options"></a>
### List what time can be for

`list_time_allocation_options` · **read** · Read-only

**Who sees it:** myPortal consultants only

Lists what time logged on one client account can be allocated to, as myPortal's picker does: the client's goals (with the project your practice has each in), objectives and actions, each with the goal it counts towards, and your practice's categories of work, each billable or not. Time on an objective or action counts towards its goal, and so towards that goal's project. log_client_time, update_time_entry and stop_timer take one of these as allocate_to and work_category. Narrow a long list with search. Takes organization_id: a client account from list_client_accounts.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account, by the id list_client_accounts gives. A call that names no client is refused. (at most 128 characters) |
| `search` | string | no | Only goals, objectives, actions and categories whose name holds this (1–100 characters) |

<a id="tool-get-productivity"></a>
### Get productivity

`get_productivity` · **read** · Read-only

**Who sees it:** myPortal consultants only

Shows productivity in the signed-in consultant's myPortal practice over a period (this month unless from and to are given, at most a quarter), as the Time tab's Productivity view does: for each person, the hours available to them (their working days, less leave and reduced hours), the billable and non-billable hours they logged, productivity (billable over available) and utilization (all logged over available) against their target, their own or the practice's, and how many hours they are over or short. The practice owner sees everyone and the practice as a whole; anyone else sees only themselves. Name one person with person ('me', a name or an id). Your practice's people only. Billable hours, never rates or money.

| Input | Type | Required | Description |
|---|---|---|---|
| `from` | string | no | The period's first day, YYYY-MM-DD; with to. Left out, this month in your practice's time zone |
| `to` | string | no | The period's last day, YYYY-MM-DD; at most a quarter after from |
| `person` | string | no | 'me', or one of your practice's people by name or id; left out, everyone you may see (1–200 characters) |

<a id="tool-list-projects"></a>
### List projects

`list_projects` · **read** · Read-only

**Who sees it:** myPortal consultants only

Lists your myPortal practice's projects, in hours: each one's client, status, hours allocated, hours logged against its goals, hours left, how much of the allocation is used, how far its goals have got, its pace (over budget, running hot when hours are used faster than the goals move, on track, no allocation, not started), dates, and each goal with its hours. Across your book (active and completed, trouble first), or every project on one client with organization_id. Filter by pace. Hours only: a project's price, cost and gross profit stay in myPortal. Projects on clients whose admins switched assistants off, or that aren't in your own book, are counted but never named.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | One client account's projects, every status; left out, every active and completed project across your book, trouble first (at most 128 characters) |
| `pace` | one of `over-budget`, `running-hot`, `on-track`, `no-allocation`, `not-started` | no | Only projects at this pace |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-list-billing"></a>
### List what to invoice

`list_billing` · **read** · Read-only

**Who sees it:** myPortal consultants only

Lists your myPortal practice's billing schedule: project milestones, add-on charges and clients' monthly retainer fees to invoice in a period, those invoiced and not yet paid, and those paid, each with its client, project, amount ex-tax, date, status and the invoice it went out on, and the totals. This month unless from and to are given; across your book, one client with organization_id, or one project's whole schedule, whatever the dates, with project. GPS issues no invoices and takes no payments: invoices are raised in the practice's own invoicing platform (Ignition, Xero and the like), and record_invoicing records each invoice's number and link back here. The schedule only: never rates, cost, gross profit or margins. Clients whose admins switched assistants off, or that aren't in your own book, are counted but never named, and are in no total.

| Input | Type | Required | Description |
|---|---|---|---|
| `view` | one of `to-invoice`, `outstanding`, `paid`, `all` | no | to-invoice: planned and dated in the period; outstanding: invoiced and not yet paid, whenever dated; paid: paid in the period; all (the default) (default `all`) |
| `from` | string | no | The period's first day, YYYY-MM-DD, with to; left out, this month in your practice's time zone |
| `to` | string | no | The period's last day, YYYY-MM-DD |
| `organization_id` | string | no | One client account's schedule; left out, every client in your book (at most 128 characters) |
| `project` | string | no | One project's whole schedule, by id or name, whatever the dates (no from or to): everything still to bill on it, what's owed and what's paid (1–200 characters) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-get-client-pnl"></a>
### Get a client's P&L

`get_client_pnl` · **read** · Read-only

**Who sees it:** myPortal consultants only

Shows one client account's profit and loss in myPortal, month by month and in total, as its drill-down shows the practice owner: revenue by source (time at client rates, fixed-price milestones, add-ons, the monthly retainer), direct costs (labor at base rates, add-on costs, expenses), gross profit and GP% (withheld where any hours have no base rate), the tax charged on the revenue, and the hours with no rate that are left out of the figures. The last six months unless from and to are given (YYYY-MM, at most 24). The practice owner only, as in myPortal: anyone else is refused. Gross, not net: no overheads. Totals by month, never a person's rate. Needs cost tracking on in the practice's Time & $ settings. Takes organization_id: a client account from list_client_accounts.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account, by the id list_client_accounts gives. A call that names no client is refused. (at most 128 characters) |
| `from` | string | no | The first month, YYYY-MM, with to; left out, the last six months to this one |
| `to` | string | no | The last month, YYYY-MM; at most 24 months after from |

<a id="tool-add-client-note"></a>
### Add a client note

`add_client_note` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** myPortal consultants, write connections only

Adds a note to your practice's journal on one client account in myPortal, where the account's History panel keeps it: a note, a decision or a risk, as plain text up to 4,000 characters, hidden from any other practice that holds the same client. It isn't hidden from the client: their own Owners and Super Admins may be able to open the journal in myPortal, so keep anything they mustn't read out of it. Name the client with organization_id (list_client_accounts gives the ids). A consultant with no seat in the client may add one. It can't be pinned or edited from here; a note is withdrawn, never edited, in myPortal. An identical note repeated within ten minutes isn't added twice. Nothing goes out: GPS sends no one a notice or an email because of this.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account, by the id list_client_accounts gives. A call that names no client is refused. (at most 128 characters) |
| `body` | string | yes | What to note, as plain text: at most 4,000 characters (1–4000 characters) |
| `kind` | one of `note`, `decision`, `risk` | no | note (the default), decision or risk (default `note`) |

<a id="tool-raise-client-action"></a>
### Raise actions with a client

`raise_client_action` · **write** · Changes GPS · Adds, never replaces · Emails people

**Who sees it:** myPortal consultants, write connections only

Asks a client for things through myPortal: raises up to 25 actions at once in one client account's Actions board, all together or none. Each is assigned to the client people named (names, emails or ids of people in that account) and to you, and can be filed under one of the client's live objectives (its id or exact name), which puts it in their plan. Due dates run from the client's today. A title can't hold a web or email address, as titles go into an email: put links in the description. Named client people get a notice in GPS now and one email gathering what was assigned to them in the next 10 minutes, sent within about 15 minutes unless their settings or quiet hours stop it; you are never notified. The account's webhooks get action.created. Refused when you already asked this client for an open action with the same title. Needs a seat in the client account, and a role above Viewer. Returns the actions with links, and exactly what went out to whom.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account: an id from list_client_accounts. Needed: a raise is never made in a default organization. (at most 128 characters) |
| `actions` | array of object | yes | What to ask, one action each, at most 25. They are raised together, or none is (1–25 items) |
| `actions[].title` | string | yes | What is asked of the client (1–200 characters) |
| `actions[].description` | string | no | More about the ask, at most 2,000 characters (at most 2000 characters) |
| `actions[].due_date` | string | no | The day it is due, YYYY-MM-DD, from the client's today on |
| `actions[].priority` | one of `high`, `medium`, `low` | no | high, medium or low; medium when left out |
| `objective` | string | no | The client's objective these serve: its id, or its exact name. Left out, they go on the client's Actions board but not in their plan (1–300 characters) |
| `assignees` | array of string | no | Who at the client is asked: names, emails or ids of people in the client account. You are added to every action as well (at most 25 items) |

<a id="tool-create-document-request"></a>
### Create a document request

`create_document_request` · **write** · Changes GPS · Adds, never replaces · Emails people

**Who sees it:** myPortal consultants, write connections only

Asks people in a client account to upload documents, as myPortal's Request Documents dialog does: a title, the documents wanted (each required unless said otherwise), a due date and the people to ask. send is required. send: true asks them now: each gets a notice in GPS and an email listing what is wanted, and GPS reminds them before and after the due date until everything is in; the answer lists every message and reminder, to whom and when. send: false saves a draft that tells nobody. A client organization's admin can let assistants save drafts only: there send: true is refused and send: false still works. Due dates are days in the client's calendar, today or later and within a year. A request your practice already has unsettled for the same client with the same title isn't made twice. Needs a seat in the client account, and a role above Viewer. It can't be undone from here, since it may already have emailed people: myPortal can pause or resume its reminders.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account, by the id list_client_accounts gives. A call that names no client is refused. (at most 128 characters) |
| `title` | string | yes | What the request is called, as the people asked will see it: at most 160 characters (1–160 characters) |
| `description` | string | no | A note to the people asked, shown in the request and its email: at most 2,000 characters (at most 2000 characters) |
| `documents` | array of object | yes | What to ask for, 1 to 40 documents, each named once (1–40 items) |
| `documents[].label` | string | yes | The document, as the people asked will see it: at most 160 characters (1–160 characters) |
| `documents[].description` | string | no | More about it: which months, which account (at most 1000 characters) |
| `documents[].required` | boolean | no | True (the default) unless it is only nice to have: reminders chase every document (default `true`) |
| `due_on` | string | no | The day it is due, YYYY-MM-DD, in the client's own calendar: today or later, within a year. Needed to send |
| `recipients` | array of string | no | The people in the client account to ask: names, emails or ids, at most 25. Needed to send (at most 25 items) |
| `send` | boolean | yes | Required. true: ask them now, and GPS reminds them until everything is in. false: save a draft that tells nobody |

<a id="tool-preview-strategy-template"></a>
### Preview a strategy template

`preview_strategy_template` · **preview** · Read-only · Previews `apply_strategy_template`, changes nothing

**Who sees it:** myPortal consultants, write connections only

Previews applying one of Empiraa's shipped strategy templates to a client account's plan, without changing anything: the goals, objectives and sub-objectives it would create, the owners, dates, tracking period and measurement types it would use, what won't carry across (written targets, goal owners, check-in reminders), problems (an objective with nobody to own it, a measurement type the client lacks), and warnings such as a goal of the same name already in the plan or the template applied there before. Takes the client's organization_id and the template's slug, id or exact name; added_objectives adds your own objectives under its goals, or sub-objectives under its objectives. When nothing stops it, returns a preview_token that apply_strategy_template applies once, within 15 minutes; a connection that can't apply it here still sees the outline, with apply_blockers saying why. At most 25 goals and objectives (sub-objectives count) can be applied at once. A practice's own templates are applied in myPortal.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `template` | string | yes | The shipped template: its slug (such as sales-1), its id, or its exact name (1–200 characters) |
| `exclude_goals` | array of string | no | Goals of the template to leave out, by exact title; their objectives go too (at most 20 items) |
| `default_owners` | array of string | no | Who owns every objective not given its own owners: people in the client account ('me', names, emails or ids) (1–10 items) |
| `objective_owners` | array of object | no | Owners for particular objectives, in place of default_owners (at most 25 items) |
| `objective_owners[].objective` | string | yes | An objective of the template, sub-objectives included, by its exact title (1–200 characters) |
| `objective_owners[].owners` | array of string | yes | (1–10 items) |
| `date_strategy` | one of `quarter`, `half`, `year`, `custom` | no | The window every goal and objective gets: the next 3, 6 or 12 months from the day it is applied, or custom dates (default `quarter`) |
| `start_date` | string | no | With date_strategy custom: the first day |
| `due_date` | string | no | With date_strategy custom: the due day |
| `tracking_period` | one of `total`, `weekly`, `monthly`, `yearly` | no | How every objective's progress is tracked (default `total`) |
| `measurement_types` | array of object | no | A measurement type the client has, in place of the template's, for particular objectives (at most 25 items) |
| `measurement_types[].objective` | string | yes | An objective of the template, sub-objectives included, by its exact title (1–200 characters) |
| `measurement_types[].type` | string | yes | (1–100 characters) |
| `missing_type_fallback` | string | no | A measurement type the client has, for every objective whose own type the client lacks and that measurement_types doesn't cover (1–100 characters) |
| `added_objectives` | array of object | no | Objectives of the consultant's own to add while applying: under one of the template's goals, or with parent_objective as a sub-objective of one of its objectives, whose progress then rolls up from its sub-objectives. Each takes the plan's window and tracking period (at most 25 items) |
| `added_objectives[].goal` | string | yes | The template goal it goes under, by exact title (1–200 characters) |
| `added_objectives[].parent_objective` | string | no | To add a sub-objective: the objective of that goal it goes under, by exact title (the template's own or one added here). Sub-objectives go one level deep (1–200 characters) |
| `added_objectives[].title` | string | yes | Its title: not one the template already uses (1–200 characters) |
| `added_objectives[].description` | string | no | (at most 1000 characters) |
| `added_objectives[].measurement_type` | string | yes | A measurement type the client has (1–100 characters) |
| `added_objectives[].owners` | array of string | no | Who owns it, in place of default_owners (1–10 items) |

<a id="tool-apply-strategy-template"></a>
### Apply a previewed strategy template

`apply_strategy_template` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** myPortal consultants, write connections only

Applies a strategy template to a client account's plan exactly as preview_strategy_template showed it, from its preview_token, once: it creates the goals, objectives and sub-objectives, with the owners, window, tracking period and measurement types the preview fixed, in one go, as myPortal's Apply does. Nothing is created if the template or the client's account has changed since the preview. Needs a seat in the client whose role can create goals and objectives. Nobody is notified and nothing is emailed. Answers with every goal and objective created and a link to each; undo is in GPS, for the whole template at once.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `preview_token` | string | yes | The preview_token preview_strategy_template returned |

<a id="tool-log-client-time"></a>
### Log time on a client

`log_client_time` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** myPortal consultants, write connections only

Logs your own time on a client account in myPortal, as its Time panel, timesheet and timer do. Give minutes, or started_at and ended_at for past time with its times. Optionally its kind of work (work_category, one of your practice's categories, which decides whether it is billable), what it was for (allocate_to a goal, objective or action on the client's plan) and what came of it (outcome, next_steps). Your practice's rounding applies; with no day given it is dated today in your practice's time zone, or the day it started. A later day, or a week already submitted, approved or locked, is refused. Hours only: no rate, cost or money. The entry is not private: it, its note and your name are listed to everyone who holds the account in myPortal, your colleagues, another practice sharing the client and the client's own founder included. Only GPS's log of AI changes keeps this change to you; add_client_note keeps a remark to your practice. Nothing goes out. Takes organization_id, from list_client_accounts.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account, by the id list_client_accounts gives. A call that names no client is refused. (at most 128 characters) |
| `minutes` | integer | no | Whole minutes worked, 1 to 1,440; your practice's rounding applies. Give this, or started_at and ended_at. (1–1440) |
| `started_at` | string (date-time) | no | When the work started, ISO 8601 with its offset, for time logged with its times; ended_at with it, and no minutes |
| `ended_at` | string (date-time) | no | When the work ended, ISO 8601 with its offset, no later than now; the minutes are the time between |
| `occurred_on` | string | no | The day the work was done, YYYY-MM-DD, up to today in your practice's time zone. Left out, it is today there, or the day started_at falls on. |
| `note` | string | no | What you did, at most 500 characters. Not private: everyone who holds this account in myPortal reads it, another practice sharing the client and the client's own founder included; add_client_note keeps a remark to your practice. (at most 500 characters) |
| `outcome` | string or null | no | What came of it, at most 1000 characters |
| `next_steps` | string or null | no | What happens next, at most 1000 characters |
| `allocate_to` | object or null | no | What the time was for on the client's plan; list_time_allocation_options lists what it can be |
| `allocate_to.kind` | one of `goal`, `objective`, `action` | yes | goal, objective or action |
| `allocate_to.item` | string | yes | Its id, or its exact title, on this client's plan (1–500 characters) |
| `work_category` | string or null | no | Its kind of work: one of your practice's categories, by name or id, which decides whether the time is billable |

<a id="tool-preview-timesheet-entries"></a>
### Preview timesheet entries

`preview_timesheet_entries` · **preview** · Read-only · Previews `fill_timesheet`, changes nothing

**Who sees it:** myPortal consultants, write connections only

Previews logging time on the signed-in consultant's own myPortal timesheet, up to 25 entries at once, each one client on one day ('today', 'yesterday' or a date, in the practice's time zone), in hours or minutes, with an optional note. Nothing is logged. Each entry is checked as logging it would be: a day after the practice's today is refused; so is a day in a week that is submitted, approved or past the practice's lock (in myPortal's words), a client whose assistants are view only, a client where your role is Viewer, and a day that already has time on that client, since filling never writes over time already there (update_time_entry changes it). The practice's rounding is shown. Nothing is copied from another week: hours come only from the entries given; last week's clients with no time this week are suggested by name only. Returns a preview_token per client, which fill_timesheet applies in that client, once, within 15 minutes.

| Input | Type | Required | Description |
|---|---|---|---|
| `entries` | array of object | yes | Up to 25 entries, each one client on one day (1–25 items) |
| `entries[].client` | string | yes | The client account: its organization_id, or its exact name (1–200 characters) |
| `entries[].day` | string | yes | 'today', 'yesterday', or YYYY-MM-DD, in your practice's time zone (1–10 characters) |
| `entries[].hours` | number | no | Hours worked, such as 1.5; give hours or minutes (at most 24) |
| `entries[].minutes` | integer | no | Whole minutes worked; give hours or minutes (1–1440) |
| `entries[].note` | string | no | What it was for, at most 500 characters. Not private: everyone who holds the client in myPortal reads it. (at most 500 characters) |

<a id="tool-fill-timesheet"></a>
### Fill a timesheet

`fill_timesheet` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** myPortal consultants, write connections only

Logs the time one client's preview_token from preview_timesheet_entries holds, on the signed-in consultant's own myPortal timesheet, in that client account (organization_id, as the preview gave it beside the token): each entry exactly as previewed, through the same logging the week grid and the account's Time panel use, with the practice's rounding. If any of its days has had time logged on that client since the preview, nothing is logged and what changed is listed; a week that has been submitted or locked since refuses its entry in myPortal's words. A preview is applied once. Reports every entry: applied (with the entry as stored), refused in the preview, failed, or not attempted after a failure. The entries and their notes aren't private: everyone who holds the client in myPortal sees them. Hours only. Nothing goes out: GPS sends no one a notice or an email because of this.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account the token was issued for: the organization_id beside it in the preview's applies. A call that names no client is refused. (at most 128 characters) |
| `preview_token` | string | yes | One client's preview_token from preview_timesheet_entries |

<a id="tool-update-time-entry"></a>
### Correct a time entry

`update_time_entry` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** myPortal consultants, write connections only

Corrects one of the signed-in consultant's own myPortal time entries, by its id: its hours or minutes, its day, its note (what you did), its kind of work (work_category, one of your practice's categories, which decides whether it is billable), what it was for (allocate_to a goal, objective or action on its client's plan), or what came of it (outcome, next_steps); null clears one. As the week grid, the Time panel and the timer's Today list correct one. Only your own entries, and only in a week that is open: a week submitted, approved or past the practice's lock refuses, in myPortal's words, both where the entry is and where it would move to. A day after the practice's today is refused, as is a voided entry. Rounding isn't applied to a correction, as in myPortal. An entry that already says this is left as it is. The correction can be undone from GPS's log of AI changes while its week is open. The entry isn't private: everyone who holds the client in myPortal sees it. Hours only. Nothing goes out.

| Input | Type | Required | Description |
|---|---|---|---|
| `entry_id` | string | yes | The entry's id, from get_my_timesheet's day or get_time_report's detailed entries (1–64 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |
| `hours` | number | no | The hours it should say, such as 1.5; give hours or minutes (at most 24) |
| `minutes` | integer | no | The whole minutes it should say (1–1440) |
| `day` | string | no | Move it to this day: 'today', 'yesterday' or YYYY-MM-DD, in your practice's time zone (1–10 characters) |
| `note` | string or null | no | What you did, as it should say; null or empty clears it |
| `outcome` | string or null | no | What came of it, at most 1000 characters |
| `next_steps` | string or null | no | What happens next, at most 1000 characters |
| `allocate_to` | object or null | no | What the time was for on the client's plan; list_time_allocation_options lists what it can be |
| `allocate_to.kind` | one of `goal`, `objective`, `action` | yes | goal, objective or action |
| `allocate_to.item` | string | yes | Its id, or its exact title, on this client's plan (1–500 characters) |
| `work_category` | string or null | no | Its kind of work: one of your practice's categories, by name or id, which decides whether the time is billable |

<a id="tool-void-time-entry"></a>
### Void a time entry

`void_time_entry` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** myPortal consultants, write connections only

Voids one of the signed-in consultant's own myPortal time entries, by its id, as the Time panel's delete does: its hours become zero and it stops counting toward the week, the account's allocation and every total, while it stays listed as voided with what it said before. It isn't deleted. Only your own entries, and only in a week that is open: a week submitted, approved or past the practice's lock refuses, in myPortal's words. An entry already voided is left as it is. The void can be undone from GPS's log of AI changes while its week is open. Hours only. Nothing goes out.

| Input | Type | Required | Description |
|---|---|---|---|
| `entry_id` | string | yes | The entry's id, from get_my_timesheet's day or get_time_report's detailed entries (1–64 characters) |
| `organization_id` | string | no | The organization (an id from list_organizations). Leave it out to use the connection's default, or the item's own organization. (at most 128 characters) |

<a id="tool-submit-timesheet-week"></a>
### Submit or withdraw my timesheet

`submit_timesheet_week` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** myPortal consultants, write connections only

Submits the signed-in consultant's own myPortal timesheet week for approval (this week unless another is named), or withdraws a submitted week before anyone acts on it, as the week grid's own buttons do. Submitting freezes the week's total, locks it against new time and corrections, and tells the practice's approvers in GPS (a notice in the app, never an email); a week sent back can be submitted again. A week already where it was asked to be is left as it is; an approved week can't be submitted or withdrawn (an approver reopens it), and a week that hasn't started can't be submitted. A week is in no client: this acts in the practice's own organization. Only your own week. Hours only.

| Input | Type | Required | Description |
|---|---|---|---|
| `week` | string | no | 'this', 'last', or any day in the week as YYYY-MM-DD; weeks run Monday to Sunday in your practice's time zone (1–10 characters) |
| `action` | one of `submit`, `withdraw` | yes | submit sends the week for approval; withdraw pulls a submitted week back before anyone acts |
| `organization_id` | string | no | Your practice's own organization; left out, it is found from your practice. Timesheets are never in a client's organization. (at most 128 characters) |

<a id="tool-review-timesheet-week"></a>
### Review a timesheet week

`review_timesheet_week` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** myPortal consultants, write connections only

Approves, returns or reopens one person's myPortal timesheet week, as an approver does in myPortal's Approvals: approve a submitted week; return a submitted week to its person with a reason they are shown in a GPS notice (in the app, never an email); reopen an approved week so it takes corrections again. Only your practice's approvers (whoever holds the subscription, and the people they name) may, and never on their own week. Name the person by consultant_id or name and the week by any day in it. A week already where it was asked to be is left as it is. The week's split by client is in get_time_report, for that person and week. A week is in no client: this acts in the practice's own organization. Hours only.

| Input | Type | Required | Description |
|---|---|---|---|
| `person` | string | yes | Whose week: their consultant_id, or their name (1–200 characters) |
| `week` | string | yes | 'this', 'last', or any day in the week as YYYY-MM-DD; weeks run Monday to Sunday in your practice's time zone (1–10 characters) |
| `action` | one of `approve`, `return`, `reopen` | yes | approve a submitted week; return a submitted week with a reason; reopen an approved week so it takes corrections again |
| `note` | string | no | Why it is going back: required to return a week, and shown to the person (at most 1000 characters) |
| `organization_id` | string | no | Your practice's own organization; left out, it is found from your practice. Timesheets are never in a client's organization. (at most 128 characters) |

<a id="tool-start-timer"></a>
### Start my timer

`start_timer` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** myPortal consultants, write connections only

Starts the signed-in consultant's myPortal timer on one client account, as the header's Track time does, with an optional note of what it's for. One timer per person: while one is running anywhere this is refused, rather than stopping it as myPortal's own start does. stop_timer logs its time first. The time is written when it stops, with your practice's rounding. Nothing goes out. Takes organization_id: a client account from list_client_accounts.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account, by the id list_client_accounts gives. A call that names no client is refused. (at most 128 characters) |
| `note` | string | no | What you are working on: it becomes the entry's note when the timer stops (at most 500 characters) |

<a id="tool-update-timer"></a>
### Change my running timer

`update_timer` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** myPortal consultants, write connections only

Changes the signed-in consultant's running myPortal timer, as the header's timer does: moves it to another client account (move_to, the commonest fix for starting on the wrong client) and/or changes its note. Its start time is kept. The client it moves to must be in your own book, with assistants able to make changes there. Takes organization_id: the client the timer is running on now (get_my_day says). Nothing goes out.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account the timer is running on now, by the id get_my_day gives (at most 128 characters) |
| `move_to` | string | no | Another client account to move it to, by id; its start time is kept (1–128 characters) |
| `note` | string or null | no | What it should say it is for; null or empty clears it |

<a id="tool-stop-timer"></a>
### Stop my timer

`stop_timer` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** myPortal consultants, write connections only

Stops the signed-in consultant's running myPortal timer and logs its time on its client, as the header's Stop does, with your practice's rounding: optionally with what you did (note), its kind of work (work_category, one of your practice's categories, which decides whether it is billable), what it was for (allocate_to a goal, objective or action) and what came of it (outcome, next_steps). Under a minute is a mis-click: nothing is logged and the timer is cleared. A week already submitted, approved or locked refuses, and the timer keeps running. Hours only. The entry isn't private: everyone who holds the client in myPortal sees it. Undo voids it while its week is open. Nothing goes out. Takes organization_id: the client the timer is running on.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account the timer is running on, by the id get_my_day gives (at most 128 characters) |
| `note` | string | no | What you did, replacing the timer's own note (at most 500 characters) |
| `outcome` | string or null | no | What came of it, at most 1000 characters |
| `next_steps` | string or null | no | What happens next, at most 1000 characters |
| `allocate_to` | object or null | no | What the time was for on the client's plan; list_time_allocation_options lists what it can be |
| `allocate_to.kind` | one of `goal`, `objective`, `action` | yes | goal, objective or action |
| `allocate_to.item` | string | yes | Its id, or its exact title, on this client's plan (1–500 characters) |
| `work_category` | string or null | no | Its kind of work: one of your practice's categories, by name or id, which decides whether the time is billable |

<a id="tool-create-time-category"></a>
### Add a time category

`create_time_category` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** myPortal consultants, write connections only

Adds a category of work to the signed-in consultant's myPortal practice, as the time picker's inline add does: a name (Admin, Travel, Client email) and whether time in it is billable. Anyone in the practice can add one, and everyone in it can then log time against it (work_category on log_client_time, update_time_entry and stop_timer). A name already used is refused, archived ones included; renaming or archiving one stays in myPortal's Time settings. A category is the practice's, in no client: this acts in the practice's own organization. Undo archives it while it is unchanged. Nothing goes out.

| Input | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | The category, such as Admin or Travel, at most 80 characters (1–80 characters) |
| `billable` | boolean | no | Whether time in it counts as billable (default yes) (default `true`) |
| `organization_id` | string | no | Your practice's own organization; left out, it is found from your practice. Categories are never in a client's organization. (at most 128 characters) |

<a id="tool-create-project"></a>
### Create a project

`create_project` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** myPortal consultants, write connections only

Creates a project on one client account in the signed-in consultant's myPortal practice, as the client's Time & Projects tab does: a name, the client's goals it covers (time on them, and on their objectives and actions, counts towards it), an hours allocation, dates and a note. Hours only: a project's fixed price is set in myPortal, never here. A goal already in another of your practice's projects is refused. Undo archives it while it is unchanged. Nothing goes out. Takes organization_id: a client account from list_client_accounts.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account, by the id list_client_accounts gives. A call that names no client is refused. (at most 128 characters) |
| `name` | string | yes | (1–200 characters) |
| `goals` | array of string | no | The client's goals it covers, by id or exact title; a goal can be in one of your practice's projects only (at most 50 items) |
| `budget_hours` | number or null | no | The hours allocated to it, such as 40; null clears it |
| `starts_on` | string or null | no | YYYY-MM-DD |
| `ends_on` | string or null | no | YYYY-MM-DD, on or after starts_on |
| `note` | string or null | no |  |

<a id="tool-update-project"></a>
### Change a project

`update_project` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** myPortal consultants, write connections only

Changes one of the signed-in consultant's practice's projects on a client account in myPortal, by its id or exact name: its name, the goals it covers (replacing them), its hours allocation, dates, note, or whether it is active or completed. Hours only: its price is set in myPortal, never here, and archiving or removing a project stays there too. A goal already in another of your practice's projects is refused. Undo puts the fields back while the project is unchanged since. Nothing goes out. Takes organization_id: the project's client account.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account, by the id list_client_accounts gives. A call that names no client is refused. (at most 128 characters) |
| `project` | string | yes | The project, by id or exact name, on this client (1–200 characters) |
| `name` | string | no | (1–200 characters) |
| `goals` | array of string | no | The client's goals it should cover, replacing the ones it has, by id or exact title (at most 50 items) |
| `budget_hours` | number or null | no | The hours allocated to it, such as 40; null clears it |
| `starts_on` | string or null | no | YYYY-MM-DD; null clears it |
| `ends_on` | string or null | no | YYYY-MM-DD; null clears it |
| `note` | string or null | no |  |
| `status` | one of `active`, `completed` | no | active, or completed; archiving one stays in myPortal |

<a id="tool-record-invoicing"></a>
### Record invoicing

`record_invoicing` · **write** · Changes GPS · Can't be undone by the assistant

**Who sees it:** myPortal consultants, write connections only

Records, in myPortal's billing schedule, the invoice a project milestone, add-on charge or retainer month went out on: moves it on to invoiced (the invoice was raised) or paid (the money came in), with the invoice number and a link to it in your practice's own invoicing platform, as the Time & $ tab does. One item a call, by its kind and id from list_billing. Moving on dates the step today in your practice's time zone unless it already had a date; it is never moved back here (myPortal does that). GPS issues no invoices and takes no payments: this only records one raised elsewhere. Undo puts it back as it was while it is unchanged since. The schedule only, never cost. Nothing goes out. Takes organization_id: the item's client account.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account, by the id list_client_accounts or list_billing gives. A call that names no client is refused. (at most 128 characters) |
| `kind` | one of `milestone`, `add_on`, `retainer_month` | yes | Which kind of item, as list_billing gives it |
| `id` | string | yes | Its id, as list_billing gives it (1–64 characters) |
| `status` | one of `invoiced`, `paid` | no | Move it on to invoiced (the invoice went out) or paid (the money came in) |
| `invoice_reference` | string or null | no | The invoice number in your practice's platform, such as INV-1042; null or empty clears it |
| `invoice_url` | string or null | no | A link to the invoice there, https only; null or empty clears it |

<a id="tool-add-milestone"></a>
### Add a billing milestone

`add_milestone` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** myPortal consultants, write connections only

Adds a milestone to one of your practice's projects on a client account in myPortal, as the project's billing schedule does: a part of its price, by name, amount ex-tax and the day it counts on. It starts planned (to invoice), and record_invoicing moves it on once the invoice is raised in your practice's own invoicing platform. GPS issues no invoices and takes no payments. It can't be undone from GPS: myPortal removes one. Nothing goes out. Takes organization_id: the project's client account.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account, by the id list_client_accounts or list_billing gives. A call that names no client is refused. (at most 128 characters) |
| `project` | string | yes | The project, by id or exact name, on this client (1–200 characters) |
| `name` | string | yes | (1–120 characters) |
| `amount` | number | yes | Ex-tax, in your practice's currency, such as 1500 or 1500.50 (0–1000000000) |
| `due_on` | string | no | The day it counts on, YYYY-MM-DD; left out, it has no date yet |

<a id="tool-add-add-on"></a>
### Add an add-on charge

`add_add_on` · **write** · Changes GPS · Adds, never replaces

**Who sees it:** myPortal consultants, write connections only

Adds an add-on charge to a client account in myPortal, as the Time & $ tab does: what it is for, what the client is charged ex-tax, the day it happened, and optionally a project on the client and a type (a new type name is added for your practice). Never a cost: what an add-on cost the practice is recorded in myPortal. It starts planned (to invoice), and record_invoicing moves it on once the invoice is raised in your practice's own invoicing platform. GPS issues no invoices and takes no payments. It can't be undone from GPS: myPortal removes one. Nothing goes out. Takes organization_id: a client account from list_client_accounts.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The client account, by the id list_client_accounts or list_billing gives. A call that names no client is refused. (at most 128 characters) |
| `description` | string | yes | What the client is charged for (1–200 characters) |
| `amount` | number | yes | What the client is charged, ex-tax, in your practice's currency: more than nothing (an expense is the owner's, in myPortal) (0–1000000000) |
| `occurred_on` | string | no | The day it happened, YYYY-MM-DD; left out, today in your practice's time zone |
| `project` | string | no | A project on this client it belongs to, by id or exact name (1–200 characters) |
| `type` | string | no | Its type, such as Travel or Software; a name your practice doesn't use yet is added as a new type (1–80 characters) |

<a id="what-changed"></a>
## What changed

What's gone off track, and what changed in GPS recently.

<a id="tool-list-status-changes"></a>
### List status changes

`list_status_changes` · **read** · Read-only

**Who sees it:** Everyone

Lists the objectives whose status changed since a day (default 7 days ago, at most 90): what each was then, from GPS's daily record, against its badge now. By default only those that got worse (on track to off track or overdue); 'newly off track' is direction worse with to_status off_track and overdue. Filter by goal or owner. Overdue first. Only objectives this person's objective list shows. Says what GPS has recorded (coverage). GPS treats every objective as higher-is-better. For one where lower is better (churn, costs, defects), passing the target shows as Completed, getting better can show as falling behind, and getting worse can show as recovering. For one of those, ask with direction any: its getting worse can be listed as better, not worse. caveats repeats this whenever one could be in scope. Titles and names are text people wrote.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to read (an id from list_organizations). Leave it out to use the connection's default organization. (at most 128 characters) |
| `since` | string | no | From when: a date (YYYY-MM-DD, the start of that day where the organization is) or an ISO 8601 date-time. Default 7 days ago; at most 90 days back. (1–40 characters) |
| `direction` | one of `worse`, `better`, `any` | no | worse (the default: on track → off track → overdue), better (back on track, or completed), or any. (default `worse`) |
| `to_status` | array of one of `on_track`, `off_track`, `overdue`, `not_started`, `started`, `completed` | no | Only objectives whose status now is one of these. Newly off track is direction worse with to_status off_track and overdue. (1–6 items) |
| `goal` | string | no | Only objectives under this goal: its id or exact title. (1–300 characters) |
| `owner` | string | no | Only objectives assigned to this person: 'me', their name, email or id. (1–200 characters) |
| `include_new` | boolean | no | Also list objectives GPS first saw after since, which have no earlier status to compare with. (default `false`) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="tool-list-recent-changes"></a>
### List recent changes

`list_recent_changes` · **read** · Read-only

**Who sees it:** Everyone

Lists what changed in one organization and who changed it, newest first (default the last 7 days, at most 90): check-ins and status changes on objectives, actions created and completed, comments, archived objectives, files, and what AI assistants changed (marked via assistant, with undone ones marked reverted). Each row only as GPS would show it to this person. Filter by kinds, objective, or by a person ('me') or 'assistant'. Paged. Summaries quote titles and text people wrote.

| Input | Type | Required | Description |
|---|---|---|---|
| `organization_id` | string | no | The organization to read (an id from list_organizations). Leave it out to use the connection's default organization. (at most 128 characters) |
| `since` | string | no | From when: a date (YYYY-MM-DD, the start of that day where the organization is) or an ISO 8601 date-time. Default 7 days ago; at most 90 days back. (1–40 characters) |
| `until` | string | no | Up to (not including): a date (the start of that day where the organization is) or an ISO 8601 date-time. Default now. (1–40 characters) |
| `kinds` | array of one of `check_in`, `status_change`, `period_result`, `action`, `objective`, `goal`, `comment`, `file`, `meeting`, `idea` | no | Only these kinds of change. Default every kind (period_result needs include_automatic). (1–10 items) |
| `objective` | string | no | Only changes about this objective: its id or exact title. (1–300 characters) |
| `by` | string | no | Only changes by this person ('me', a name, email or id), or 'assistant' for changes made through AI assistants. (1–200 characters) |
| `include_automatic` | boolean | no | Also list the results GPS writes when a weekly or monthly objective's period ends. (default `false`) |
| `response_format` | one of `concise`, `detailed` | no | concise (the default) returns the essentials; detailed adds descriptions and every field. (default `concise`) |
| `limit` | integer | no | How many to return, 1 to 100 (default 25). (1–100) (default `25`) |
| `cursor` | string | no | The next_cursor of the previous page, to continue from it. Leave it out for the first page. (at most 512 characters) |

<a id="search"></a>
## Search

Search across GPS, and open one result.

<a id="tool-search"></a>
### Search GPS

`search` · **read** · Read-only

**Who sees it:** Everyone

Searches everything the connected person can see in Empiraa GPS, across every organization this connection reaches (client accounts included): objectives, goals, actions, meetings, improvement ideas, people and files, each where its own list in GPS would show it to them. Matches every word of the query in titles and descriptions (people by name, email or job title), best match first, at most 20. Each result's id opens with fetch; its title says what kind of item it is, its status, due date or role, and its organization. Titles and organization names are text people wrote.

| Input | Type | Required | Description |
|---|---|---|---|
| `query` | string | yes | Words to look for in titles and descriptions (and people's names, emails and job titles). Two characters at least. (1–200 characters) |

<a id="tool-fetch"></a>
### Fetch from GPS

`fetch` · **read** · Read-only

**Who sees it:** Everyone

Opens one item search returned, by its id (<type>:<id>), as a readable record: what it is and where, its key facts (status, progress, dates, owners and the like) and what people wrote about it (quoted, every line starting '> '), as markdown of at most 4,000 characters, with its link in GPS and its facts as metadata. Opens objectives, goals, actions, meetings, improvement ideas, people and files the connected person may open in GPS; anything else is not found. Titles, descriptions, notes, summaries and names are text people wrote.

| Input | Type | Required | Description |
|---|---|---|---|
| `id` | string | yes | An id search returned: <type>:<id> (1–200 characters) |
