Rhythms REST API v2
REST API v2 is the Rhythms API for third-party integrations, reporting, automation and bulk changes. It offers predictable JSON endpoints under https://api.rhythms.ai/rest/v2/ for Objectives, Key Results, Initiatives, Check-ins, Labels, Teams and Users. This article mirrors the published reference at apidocs.rhythms.ai/rest/v2, where you can also send test requests. To get a token, see Get access to the Rhythms REST API.
Basics
Base URL: https://api.rhythms.ai. All REST API v2 endpoints are prefixed with /rest/v2/.
Response format: JSON. Successful responses wrap the payload in a data object. Error responses use standard HTTP status codes with a short message.
Authentication: every request needs a Bearer token in the Authorization header. The API runs each request with the permissions of the user the token belongs to.
Authorization: Bearer ‹token›Rate limiting
Rhythms does not publish fixed per-token rate limits today. Keep request volume reasonable — page with limit=100, use count=true instead of walking every page to get a total, and cache what you can. The API reserves 429 Too Many Requests; handle it with a back-off and retry. If you expect sustained high volume, tell support@rhythms.ai about the integration.
Pagination and counts
List endpoints support pagination through query parameters.
page
number
1
Page number.
limit
number
20
Records per page, maximum 100.
per_page
number
20
Alias for limit.
limit_max
number
—
Maximum records per page; used as the page size when limit is not set.
count
string
—
Set to true to include the total in data.pagy.count. Use this for totals instead of paginating through every page.
Paginated responses include metadata in data.pagy; next is the next page number, or null when there are no more pages.
Making requests
A first request
List endpoints return data.records (an array) plus data.pagy:
Single-record endpoints return data.record instead of data.records. Record fields are abbreviated above; the live docs carry the full schema.
Filtering
List endpoints accept a q parameter using bracket notation: the attribute name followed by a predicate.
_eq
exact match
_cont
contains (substring)
_in
value is in a list, e.g. q[current_status_in][]=behind&q[current_status_in][]=at_risk
_gteq / _lteq
greater than or equal / less than or equal — useful on dates
_present / _null
attribute is set / attribute is null
Add q[s]=‹attribute›+asc|desc to sort. The attribute before the predicate must be filterable for that endpoint; each section below lists the filterable attributes.
Paging
data.pagy.next holds the next page number, or null on the last page. Add count=true to include a total in data.pagy.count.
When authentication fails
A missing or invalid token returns 401:
A valid token whose user is not allowed to perform the action returns 403.
Going further
The live docs at apidocs.rhythms.ai/rest/v2 carry the full schema for every endpoint, let you send a real authenticated request from the browser, and let you load the API definition into an AI coding assistant such as Cursor.
API sections
REST API v2 has 7 sections and 34 operations.
Checkins
5
Initiatives
5
Key Results
5
Labels
5
Objectives
5
Teams
5
Users
4
Checkins
Check-ins record progress updates, status, notes, values and labels for a goal.
GET
/rest/v2/checkins
List check-ins.
POST
/rest/v2/checkins
Create a check-in.
GET
/rest/v2/checkins/{id}
Get a check-in.
PUT
/rest/v2/checkins/{id}
Update a check-in.
DELETE
/rest/v2/checkins/{id}
Delete a check-in.
List check-ins
GET /rest/v2/checkins returns check-ins newest first and supports filtering and pagination.
Filterable attributes: uuid, goal_uuid, creator_uuid, checkin_date, created_at, status, value, source_type.
Create a check-in
POST /rest/v2/checkins creates a check-in for a goal with an optional value, status and note. Fields are sent at the top level of the JSON body (no wrapper object).
goal_uuid
string
yes
UUID of the goal being checked in. (checkinable_uuid is accepted as a deprecated alias.)
timezone_offset
number
yes
Your offset from UTC in minutes, as JavaScript's getTimezoneOffset() reports it (negative east of UTC). Must be between -840 and 720.
value
number
no
Check-in value. The goal must have a metric.
status
string
no
Defaults to not_started; one of not_started, in_progress, on_track, behind, at_risk, closed, postponed.
note
string
no
Check-in note.
checkin_date
string
no
YYYY-MM-DD. Defaults to today in your timezone; cannot be in the future.
score
number
no
Score; only stored when status is closed.
progress_mode
string
no
Sets the goal's progress mode: manual, rollup or integration.
labels
array[string]
no
Label names to apply to the check-in.
Checking in on a draft goal publishes it, provided the token's user is allowed to publish it.
Get, update and delete a check-in
GET /rest/v2/checkins/{id}retrieves a check-in by UUID.PUT /rest/v2/checkins/{id}updatesvalue,status,note,scoreandlabels. At least one must be provided. A score is kept only while the status isclosed.DELETE /rest/v2/checkins/{id}deletes a check-in. If it was the goal's latest check-in, the goal's cached status and progress are recalculated.
Goals: Objectives, Key Results and Initiatives
Objectives, Key Results and Initiatives share the same core goal fields and CRUD pattern. Each type has its own endpoint namespace.
Endpoint namespaces
Objectives
/rest/v2/objectives
/rest/v2/objectives/{id}
Key Results
/rest/v2/key_results
/rest/v2/key_results/{id}
Initiatives
/rest/v2/initiatives
/rest/v2/initiatives/{id}
{id} accepts either the goal's UUID or its short ID such as OBJ-001 or KR-014. List endpoints return published goals only, ordered by title.
Shared create fields
Used by POST /rest/v2/objectives, POST /rest/v2/key_results and POST /rest/v2/initiatives. Fields are sent at the top level of the JSON body.
title
string
yes
Goal title.
description
string
no
Goal description.
time_period_uuid
string
yes
Time period UUID. Its dates define the allowed goal date range.
start_date
string
no
YYYY-MM-DD; must fall within the time period and be on or before end_date. Defaults to the period start.
end_date
string
no
YYYY-MM-DD; must fall within the time period and be on or after start_date. Defaults to the period end.
goal_type
string
no
Defaults to aspirational; one of aspirational, committed.
visibility
string
no
Defaults to public; one of public, limited.
team_uuids
array[string]
no
Team UUIDs; default [].
owner_uuids
array[string]
no
Owner UUIDs; default [].
labels
array[string]
no
Label names; default []. Unknown names are created when the token's user may create labels.
delegate_uuids
array[string]
no
Delegate UUIDs; default [].
metric
object
no
Metric configuration.
metric.name
string
no
Defaults to Progress.
metric.start_value
number
no
Defaults to 0.
metric.target_value
number
no
Defaults to 100.
metric.unit
string
no
One of percentage, number, dollar, euro, pound, swiss_franc. Defaults to number for Key Results and to percentage for Objectives and Initiatives — set it explicitly if you need a particular unit.
metric.metric_type
string
no
Defaults to reach; one of reach, stay_above, stay_below, stay_between.
parents
array[object]
no
Parent goal objects, not strings: {"uuid": "‹parent UUID›", "type": "‹parent type›", "is_contributing": true}. is_contributing is optional — omit it to use your workspace's OKR model default for this goal type. Default [].
visible_entities
array[object]
no
Who can see the goal when visibility is limited. Array of objects: {"entity_type": "User" | "Team", "entity_uuid": "<UUID>", "mode": "<visibility mode>"}. Default [].
Shared update fields
Used by PUT /rest/v2/objectives/{id}, PUT /rest/v2/key_results/{id} and PUT /rest/v2/initiatives/{id}. Update fields include title, description, goal_type, visibility, current_status, start_date, end_date, time_period_uuid, team_uuids, owner_uuids, labels, delegate_uuids, progress_mode, metric, parents and visible_entities. Only the fields you send are changed. Changing time_period_uuid resets omitted start and end dates to the new period's boundaries. When you resend parents, include every parent that should remain; a parent left out is unlinked, and a parent resent without is_contributing keeps its current contribution.
Shared delete options
Used by DELETE /rest/v2/objectives/{id}, DELETE /rest/v2/key_results/{id} and DELETE /rest/v2/initiatives/{id}. Deleting through the API removes the goal permanently — unlike deleting in the Rhythms app, it does not go to Trash and cannot be restored. Check the goal's children and links first.
including_immediate_objectives
boolean
false
Also delete immediate child objectives.
including_immediate_initiatives
boolean
false
Also delete immediate child initiatives.
including_immediate_key_results
boolean
false
Also delete immediate child key results.
delete_hierarchy
boolean
false
Delete the entire hierarchy beneath the goal.
Goal list filters
The Objective, Key Result and Initiative list endpoints support filtering on uuid, type, current_status, last_checkin_date, time_period_uuid, creator_uuid and discarded_at, plus associated filters for time periods, owners, labels, ancestors, teams, child links and delegates.
Labels
Labels can be regular labels or label groups, and can be attached to OKRs and check-ins.
GET
/rest/v2/labels
List labels and label groups.
POST
/rest/v2/labels
Create a label.
GET
/rest/v2/labels/{id}
Get a label.
PUT
/rest/v2/labels/{id}
Update a label.
DELETE
/rest/v2/labels/{id}
Delete a label.
GET /rest/v2/labels supports filtering on uuid, name, parent_uuid and is_group.
To create or update a label, send a label wrapper object. Create accepts name (required, unique in the workspace), description, parent_uuid (the parent must be a group), is_group and color (a hex code such as #eb5757). Update accepts name, description, parent_uuid and color; send a blank parent_uuid to move a label back to the root, and a blank color to clear it. Whether a label is a group cannot be changed after creation. Creating labels requires a Rhythms Admin token.
Deleting a label also deletes its child labels.
Teams
Teams can have a parent team, owners, members, and an active or archived status.
GET
/rest/v2/teams
List teams.
POST
/rest/v2/teams
Create a team.
GET
/rest/v2/teams/{id}
Get a team.
PUT
/rest/v2/teams/{id}
Update a team.
DELETE
/rest/v2/teams/{id}
Delete a team.
GET /rest/v2/teams supports filtering on uuid, display_name, parent_uuid, status, is_org and depth, plus associated team membership filters.
To create or update a team, send a team wrapper object.
Create accepts
display_name(required),description,parent_uuid,owner_uuidsandmember_uuids. A user listed in both arrays becomes a Team Owner.Update accepts the same fields plus
status, one ofactiveorarchived. Status can only be set on update, not on create. Sendingowner_uuidsreplaces the full set of Team Owners; sendingmember_uuidsadds the listed members.
A team can be deleted only if it has no active sub-teams and no OKR relationships.
Users
Users can be listed, created, retrieved and updated. REST API v2 has no user delete operation; deactivate a user by setting status to closed.
GET
/rest/v2/users
List users.
POST
/rest/v2/users
Create a user.
GET
/rest/v2/users/{id}
Get a user.
PUT
/rest/v2/users/{id}
Update a user.
GET /rest/v2/users supports filtering on uuid, display_name, status, manager_uuid and license_type, plus associated filters for direct teams, team memberships, profile fields and manager fields.
To create or update a user, send a user wrapper object.
Create requires
email(unique in the workspace) anddisplay_name. Optional:license_type(standard,hris_onlyorguest; defaultstandard),status(activeorclosed; defaultactive),manager_uuid, andprofile_attributeswithfirst_name,last_name,job_title,timezone,localeandabout.Update accepts
display_name,avatar_url(applied only when the user has no avatar yet),status,manager_uuid,license_typeandprofile_attributes.
A manager_uuid must refer to an existing user, otherwise the request returns 422.
Common response codes
200
Success.
201
Created.
400
Bad Request — invalid parameters or malformed request.
401
Unauthorized — invalid or missing token, or the token's user is no longer active.
403
Forbidden — the token's user is not allowed to perform this action in Rhythms.
404
Not Found — resource does not exist.
422
Unprocessable Entity — validation error; the body explains which rule failed.
429
Too Many Requests — back off and retry.
500
Internal Server Error — unexpected server error.
Schemas
REST API v2 references 10 response schemas: label, okrs_checkin, okrs_initiative, okrs_key_result, okrs_objective, rest_v2_goal_collection_response, rest_v2_goal_response, rest_v2_user_collection_response, rest_v2_user_response and team.
Goal schemas for objectives, key results and initiatives share a common shape with fields for UUID, type, short ID, title, description, dates, goal type, time period, current metric (target, unit and metric type), owners, visible parent links with contribution percentages, creator, status, progress, visibility, data sources and discarded metadata.
Collection response schemas wrap records in data.records and can include data.pagy, data.checks and data.filters. Single-record response schemas wrap the record in data.record and can include data.checks and data.access_source.
Related articles
Last updated
Was this helpful?