Rhythms REST API v2
Last updated: August 25, 2026
Spec version: v2
OpenAPI: 3.0.0
Base URL: https://api.rhythms.ai
This article mirrors the published API reference at apidocs.rhythms.ai/rest/v2, where you can also send test requests.
Overview
The official REST API for Rhythms is designed for third-party integrations, mobile apps, external tooling, reporting dashboards, and automation workflows. It follows REST conventions and provides predictable JSON endpoints for managing OKRs: Objectives, Key Results, Initiatives, Check-ins, Labels, Teams, and Users.
Base URL
https://api.rhythms.aiAll REST API v2 endpoints are prefixed with:
/rest/v2/Response format
All responses use JSON. Successful responses include requested data. Error responses use standard HTTP status codes with detailed troubleshooting information.
Authentication
All API endpoints require Bearer token authorization. Include this header with every request:
Authorization: Bearer <token>To obtain API credentials, contact Rhythms Support at support@rhythms.ai.
Rate limiting
Standard rate limits apply to all endpoints to ensure fair usage and performance. For higher limits, contact support@rhythms.ai with details about your integration use case.
Pagination and counts
List endpoints support pagination through query parameters.
| Parameter | Type | Default | Description |
|---|---|---|---|
page | number | 1 | Page number. |
per_page | number | 20 | Records per page, max 100. |
limit | number | 20 | Alias for per_page. |
limit_max | number | — | Maximum records per page; overrides limit when limit is not set. |
count | string | — | Set to true to include total count in data.pagy.count. Use this for total/count queries 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
Every request needs your API token in the Authorization header. If you do not have a token yet, see Accessing and Integrating with the Rhythms REST API.
A first request
curl -H "Authorization: Bearer tokp_1abc23c45d..." \
-H "Accept: application/json" \
"https://api.rhythms.ai/rest/v2/objectives?limit=1"
Successful responses wrap everything in a data object. List endpoints return data.records (an array) plus data.pagy (pagination metadata):
{
"data": {
"type": "Okrs::Objective",
"records": [
{
"uuid": "...",
"type": "Okrs::Objective",
"short_id": "OBJ-001",
"title": "Grow enterprise revenue",
"current_status": "on_track",
"start_date": "2026-07-01",
"end_date": "2026-09-30",
"owner_uuids": ["..."]
}
],
"pagy": { "next": 2 }
}
}
Single-record endpoints return data.record instead of data.records. Record fields are abbreviated above; the full set is listed per section below.
Filtering
List endpoints accept a q parameter using bracket notation. Two predicates are in common use:
_eq— exact match_cont— contains (substring)
# objectives that have not started
GET /rest/v2/objectives?q[current_status_eq]=not_started
# users whose display name contains "Alice"
GET /rest/v2/users?q[display_name_cont]=Alice
# teams whose display name contains "Engineering"
GET /rest/v2/teams?q[display_name_cont]=Engineering
# labels that are groups
GET /rest/v2/labels?q[is_group_eq]=true
The attribute before the predicate must be filterable for that endpoint. Each section below lists which attributes are available.
Paging
GET /rest/v2/objectives?page=1&limit=1
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 rather than paging through every result.
When authentication fails
A missing or invalid token returns 401:
{ "error": "Invalid Authorization header" }
Going further
The live API docs at apidocs.rhythms.ai/rest/v2 are the place to get into the weeds. They carry the full schema for every endpoint, plus two things this article cannot offer:
- Try it — send a real, authenticated request from the browser and see the actual response.
- Connect to Cursor — load the API definition into an AI coding assistant such as Cursor so it can read the endpoints and fields while you build.
API sections
REST API v2 includes 7 sections, 34 operations, and 10 response schemas.
| Section | 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.
| Method | Path | Summary |
|---|---|---|
GET | /rest/v2/checkins | List check-ins. |
POST | /rest/v2/checkins | Create a new check-in. |
GET | /rest/v2/checkins/{id} | Get a specific 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
Retrieves check-ins. Supports filtering and pagination.
Filterable attributes: uuid, goal_uuid, creator_uuid, checkin_date, created_at, status, value, source_type.
Operation ID: get_rest_v2_checkins
Create a check-in
POST /rest/v2/checkins
Creates a check-in for a goal with optional value, status, and note.
Operation ID: post_rest_v2_checkins
| Field | Type | Required | Notes |
|---|---|---|---|
goal_uuid | string | no | UUID of the goal being checked in. |
checkinable_uuid | string | no | Deprecated; use goal_uuid. |
value | number | no | Check-in value. |
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 | Date in YYYY-MM-DD format. |
timezone_offset | number | yes | Timezone offset in minutes. |
score | number | no | Score, only for closed status. |
progress_mode | string | no | One of manual, rollup, integration. |
labels | array[string] | no | Label names to apply to the check-in. |
Get, update, and delete a check-in
GET /rest/v2/checkins/{id}retrieves a check-in by UUID.PUT /rest/v2/checkins/{id}updates value, status, note, score, and labels.DELETE /rest/v2/checkins/{id}deletes a check-in.
Goals: Objectives, Key Results, and Initiatives
Objectives, Key Results, and Initiatives share the same core goal fields and CRUD patterns. Each type has its own endpoint namespace.
Endpoint namespaces
| Goal type | List/create path | Specific record path |
|---|---|---|
| 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} |
Shared create fields
Used by POST /rest/v2/objectives, POST /rest/v2/key_results, and POST /rest/v2/initiatives.
| Field | Type | Required | Notes |
|---|---|---|---|
title | string | yes | Goal title. |
description | string | no | Goal description. |
time_period_uuid | string | yes | Time period UUID. Its stored dates define the allowed goal date range. |
start_date | string | no | Optional YYYY-MM-DD; must fall within the selected time period and be on or before end_date. |
end_date | string | no | Optional YYYY-MM-DD; must fall within the selected time period and be on or after start_date. |
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 []. |
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 | Defaults to percentage; one of percentage, number, dollar, euro, pound, swiss_franc. |
metric.metric_type | string | no | Defaults to reach; one of reach, stay_above, stay_below, stay_between. |
parents | array[object] | no | Array of parent goal objects, not strings. Each element: {"uuid": "<parent goal UUID>", "type": "<parent goal type>", "is_contributing": true}. is_contributing is optional — omit it to use your workspace's OKR model default. Default []. |
visible_entities | array[object] | no | Who can see the goal when visibility is limited. Array of objects, not strings. Each element: {"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, dates, time period, teams, owners, labels, delegates, progress mode, metric, parents, and visible entities. Changing time_period_uuid resets omitted start/end dates to the new period boundaries.
Shared delete options
Used by DELETE /rest/v2/objectives/{id}, DELETE /rest/v2/key_results/{id}, and DELETE /rest/v2/initiatives/{id}.
| Field | Type | Default | Notes |
|---|---|---|---|
including_immediate_objectives | boolean | false | Include immediate objectives. |
including_immediate_initiatives | boolean | false | Include immediate initiatives. |
including_immediate_key_results | boolean | false | Include immediate key results. |
delete_hierarchy | boolean | false | Delete the entire hierarchy. |
Goal list filters
The Objective, Key Result, and Initiative list endpoints support filtering on goal fields such as uuid, discarded_at, type, current_status, last_checkin_date, time_period_uuid, and creator_uuid. They also support associated filters for time periods, owners, labels, ancestors, teams, child links, and delegates.
Labels
Labels can be regular labels or label groups. They can be attached to OKRs and check-ins.
| Method | Path | Summary |
|---|---|---|
GET | /rest/v2/labels | List labels and label groups. |
POST | /rest/v2/labels | Create a new label. |
GET | /rest/v2/labels/{id} | Get a specific 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 labels, send a label wrapper object. Label fields include name, description, parent_uuid, is_group, and color. When updating, parent_uuid can move a non-group label between groups or back to root.
Deleting a label also deletes child labels.
Teams
Teams can have parents, owners, members, and active/archived status.
| Method | Path | Summary |
|---|---|---|
GET | /rest/v2/teams | List teams. |
POST | /rest/v2/teams | Create a new team. |
GET | /rest/v2/teams/{id} | Get a specific 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. It also supports associated team membership filters.
To create or update teams, send a team wrapper object. Team fields include display_name, description, parent_uuid, status, owner_uuids, and member_uuids.
A team can be deleted only if it has no active sub-teams or OKR relationships.
Users
Users can be listed, created, retrieved, and updated. REST API v2 does not include a user delete operation.
| Method | Path | Summary |
|---|---|---|
GET | /rest/v2/users | List users. |
POST | /rest/v2/users | Create a new user. |
GET | /rest/v2/users/{id} | Get a specific 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. It also supports associated filters for direct teams, team memberships, profile fields, and manager fields.
To create or update users, send a user wrapper object. User fields include email, display_name, license_type, status, manager_uuid, avatar_url, and profile_attributes. Email is required and must be unique when creating a user.
Common response codes
| Code | Meaning |
|---|---|
200 | Success. |
201 | Created. |
400 | Bad Request — invalid parameters or malformed request. |
401 | Unauthorized — invalid or missing authentication. |
403 | Forbidden — caller lacks permission to access the resource. |
404 | Not Found — resource does not exist. |
422 | Unprocessable Entity — invalid request parameters or validation errors. |
429 | Too Many Requests — rate limit exceeded. |
500 | Internal Server Error — unexpected server error. |
Schemas
REST API v2 references 10 response schemas:
labelokrs_checkinokrs_initiativeokrs_key_resultokrs_objectiverest_v2_goal_collection_responserest_v2_goal_responserest_v2_user_collection_responserest_v2_user_responseteam
Goal schemas for objectives, key results, and initiatives share a common shape with fields for UUID, type, title, description, dates, goal type, time period, current metric, creator, status, progress, visibility, data sources, discarded metadata, and short ID.
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.