Data model
What each object in the API holds, how objects connect, and the values their status fields take. For the complete list of fields on every type, browse the full schema on Apollo Studio.
Fields every object has
Every object shares these fields, so they're not repeated in the tables below:
| Field | What it holds |
|---|---|
id | The item's ID: a UUID, used in item(id:) queries and in update mutations. |
companyId | The company the item belongs to. Required when you create anything. |
stateId | ACTIVE, or DELETED once someone deletes it. Filter on ACTIVE to match the app. |
createdAt, updatedAt | When the item was created and last changed (UTC). |
lastUpdatedByUserId | Who changed it last, as a user ID. Follow lastUpdatedByUser for their name. |
In the tables, required means you must send the field when you create the item.
Users and teams
users are the people in your company. A person has a different user ID in each company they belong to.
| Field | What it holds |
|---|---|
firstName, lastName, email, jobTitle | Who they are. |
userPermissionId | Their role: OWNER, ADMIN, MANAGER, TEAMMEMBER, OBSERVER, IMPLEMENTER and others. See the userPermissions list. |
userStatusId | ACTIVE, or INACTIVE for people who've been deactivated. |
timeZone, languageId | Their settings, such as Europe/Dublin and en. |
teams are the teams in your company. isLeadership is true for the Leadership Team. A team's people are in usersOnTeams, a linking list with one record per person per team:
query {
teams(filter: { stateId: { equalTo: "ACTIVE" } }) {
nodes {
id
name
isLeadership
usersOnTeams(filter: { stateId: { equalTo: "ACTIVE" } }) {
nodes { user { id firstName lastName } }
}
}
}
}
To add someone to a team, create a usersOnTeam with their userId, the teamId and your companyId. To take them off, set its stateId to DELETED.
To-dos
todos are 7-day action items, each owned by one person on one team.
| Field | What it holds | Required |
|---|---|---|
name | The To-do itself | |
desc | Details, as HTML. Send "" for none. | Yes |
teamId | The team it belongs to | Yes |
userId | Who owns it | |
todoStatusId | TODO (open) or COMPLETE (done) | Yes |
dueDate | YYYY-MM-DD | |
priorityNo | Priority; send 999 for none | Yes |
type | team, or private for a private To-do | |
meetingId | The meeting it was raised in | if any |
statusUpdatedAt | When its status last changed |
Follow team, user, todoStatus and meeting for the related items.
Issues
issues are the Issues List: things to discuss and solve (IDS™).
| Field | What it holds | Required |
|---|---|---|
name, desc | The Issue and its details (HTML) | |
teamId | The team whose list it's on | Yes |
userId | Who raised or owns it | Yes |
issueStatusId | TODO (not solved, the default) or COMPLETE (solved) | |
type | short-term (this week's list) or long-term (the parking lot) | |
number | The Issue's number, as shown in the app | |
priorityNo | 1 to 3 for a top-three priority, 999 for none | |
meetingId | The meeting it was raised in | if any |
Issue IDs are strings rather than UUIDs, so use String! for them in variables.
Rocks and Milestones
rocks are 90-day priorities.
| Field | What it holds | Required |
|---|---|---|
name | The Rock | |
desc | Details, as HTML. Send "" for none. | Yes |
userId | Who owns it | Yes |
dueDate | YYYY-MM-DD | Yes |
rockStatusId | ONTRACK, OFFTRACK, COMPLETE (done) or INCOMPLETE (not done) | Yes |
type | company or personal (an individual Rock) | |
isArchived | true once the Rock has been archived, usually at the end of its quarter |
A Rock can be shared with several teams, so it has no teamId. The link is in teamsOnRocks, with one record per team per Rock. To get one team's Rocks, look up the Rock IDs first:
query TeamRocks($teamId: UUID!) {
teamsOnRocks(filter: { teamId: { equalTo: $teamId }, stateId: { equalTo: "ACTIVE" } }) {
nodes { rockId }
}
}
Then fetch those Rocks, with their Milestones:
query RocksById($ids: [UUID!]) {
rocks(
filter: { id: { in: $ids }, stateId: { equalTo: "ACTIVE" }, isArchived: { equalTo: false } }
orderBy: DUE_DATE_ASC
) {
nodes {
id
name
dueDate
rockStatus { name }
user { firstName lastName }
milestones(filter: { stateId: { equalTo: "ACTIVE" } }, orderBy: DUE_DATE_ASC) {
nodes { name dueDate milestoneStatusId }
}
}
}
}
When you create a Rock, create its teamsOnRock link in the same request, or it won't appear on any team. Creating and updating data has the full example.
milestones are the steps of a Rock. Each has a rockId, name, dueDate, userId and milestoneStatusId (TODO or COMPLETE). rockId, dueDate and userId are required.
Headlines
headlines are the good news and updates shared in meetings.
| Field | What it holds | Required |
|---|---|---|
name, desc | The Headline and its details (HTML) | name: Yes |
teamId | The team it's shared with | Yes |
userId | Who shared it | Yes |
headlineStatusId | DISCUSS (not shared yet), DISCUSSED (shared) or BACKLOG | |
isCascadingMessage | true for a Cascading Message rather than a Headline |
Scorecards
A Scorecard is made of two objects:
- Measurables (
dataFields) are the rows: the number, who owns it and its goal. - Values (
dataValues) are the cells: one number per measurable per period.
| Measurable field | What it holds |
|---|---|
name, desc | What's measured |
userId | Who owns the number |
type | How often it's measured: WEEKLY, MONTHLY, QUARTERLY or ANNUALLY |
unitType | number, percentage, currency, time or yes/no |
goalTarget, unitComparison | The goal, such as 150 with >=. Comparisons: >=, <=, =, >, <. A range uses goalTargetEnd too. |
goalCurrency | The currency symbol for currency measurables, such as $ |
dataFieldStatusId | ACTIVE, or ARCHIVED once archived |
formula | Set when the number is calculated from other measurables |
Like Rocks, measurables can be on several teams. The link is in teamsOnDataFields, with a teamId and a dataFieldId.
| Value field | What it holds | Required |
|---|---|---|
dataFieldId | The measurable it belongs to | Yes |
startDate | The first day of the period, YYYY-MM-DD (see below) | Yes |
value | The number, sent as a string, such as "42" or "98.5" | |
note | A note on this value | |
customGoalTarget | A different goal for just this period |
startDate must be the exact start of the measurable's period, or the value is refused:
| Measurable type | startDate must be |
|---|---|
WEEKLY | A Monday, such as 2026-11-09 for the week of 12 November |
MONTHLY | The 1st of the month |
QUARTERLY | The first day of one of your company's quarters (by default 1 January, 1 April, 1 July and 1 October; your company may use different dates) |
ANNUALLY | 1 January |
There's one value per measurable per period. To change a number that's already there, update it rather than creating another. Recipes shows the full pattern.
Meetings
Meetings come in two parts:
meetingInfosare the recurring meetings you set up, such as a team's weekly Level 10 Meeting™. Each has aname, ateamId, anownerUserIdand the agenda it follows (meetingAgenda).meetingsare each time it takes place, with itsdate,meetingInfoId,meetingStatusId(NOT-STARTED,STARTED,PAUSEDorFINISHED),startTime,endTimeandaverageRating.
To-dos, Issues and Headlines raised in a meeting carry its meetingId, so you can list what came out of one:
query MeetingOutcomes($meetingId: UUID!) {
meeting(id: $meetingId) {
date
averageRating
todos(filter: { stateId: { equalTo: "ACTIVE" } }) { nodes { name user { firstName } } }
issues(filter: { stateId: { equalTo: "ACTIVE" } }) { nodes { name issueStatusId } }
}
}
Comments
comments are the comments on Rocks, To-dos, Issues, Headlines, Scorecard measurables and processes. Each has:
objectId: the ID of the item it's on.type: what kind of item that is:rocks,todos,issues,headlines,dataFields(Scorecard measurables) orprocesses.text: the comment, as HTML.userId: who wrote it.
To get the comments on an Issue:
query IssueComments($issueId: String!) {
comments(
filter: { objectId: { equalTo: $issueId }, type: { equalTo: "issues" }, stateId: { equalTo: "ACTIVE" } }
orderBy: CREATED_AT_ASC
) {
nodes { text createdAt user { firstName lastName } }
}
}
To add one, create a comment with objectId, type, text, userId and companyId.
Status values
Statuses are short IDs. Their display names, as the app shows them, are in a list for each kind, such as rockStatuses { nodes { id name } }.
| Field | Values |
|---|---|
todoStatusId | TODO (To-do), COMPLETE (Done) |
issueStatusId | TODO (Not solved), COMPLETE (Solved) |
rockStatusId | ONTRACK (On-track), OFFTRACK (Off-track), COMPLETE (Done), INCOMPLETE (Not done) |
milestoneStatusId | TODO (To-do), COMPLETE (Complete) |
headlineStatusId | DISCUSS (Not shared), DISCUSSED (Shared), BACKLOG (Backlog) |
meetingStatusId | NOT-STARTED, STARTED, PAUSED, FINISHED |
dataFieldStatusId | ACTIVE, ARCHIVED |
userStatusId | ACTIVE, INACTIVE |
stateId (all objects) | ACTIVE, DELETED |
Everything else
The API also covers the V/TO™ (visions and their entities), the Accountability Chart™ (accCharts, accChartSeats), processes, the People Analyzer™, SWOT items and more. These follow the same patterns, and their fields are listed in the full schema.