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.ai

All 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.

ParameterTypeDefaultDescription
pagenumber1Page number.
per_pagenumber20Records per page, max 100.
limitnumber20Alias for per_page.
limit_maxnumberMaximum records per page; overrides limit when limit is not set.
countstringSet 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.

SectionOperations
Checkins5
Initiatives5
Key Results5
Labels5
Objectives5
Teams5
Users4

Checkins

Check-ins record progress updates, status, notes, values, and labels for a goal.

MethodPathSummary
GET/rest/v2/checkinsList check-ins.
POST/rest/v2/checkinsCreate 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

FieldTypeRequiredNotes
goal_uuidstringnoUUID of the goal being checked in.
checkinable_uuidstringnoDeprecated; use goal_uuid.
valuenumbernoCheck-in value.
statusstringnoDefaults to not_started; one of not_started, in_progress, on_track, behind, at_risk, closed, postponed.
notestringnoCheck-in note.
checkin_datestringnoDate in YYYY-MM-DD format.
timezone_offsetnumberyesTimezone offset in minutes.
scorenumbernoScore, only for closed status.
progress_modestringnoOne of manual, rollup, integration.
labelsarray[string]noLabel 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 typeList/create pathSpecific 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.

FieldTypeRequiredNotes
titlestringyesGoal title.
descriptionstringnoGoal description.
time_period_uuidstringyesTime period UUID. Its stored dates define the allowed goal date range.
start_datestringnoOptional YYYY-MM-DD; must fall within the selected time period and be on or before end_date.
end_datestringnoOptional YYYY-MM-DD; must fall within the selected time period and be on or after start_date.
goal_typestringnoDefaults to aspirational; one of aspirational, committed.
visibilitystringnoDefaults to public; one of public, limited.
team_uuidsarray[string]noTeam UUIDs; default [].
owner_uuidsarray[string]noOwner UUIDs; default [].
labelsarray[string]noLabel names; default [].
delegate_uuidsarray[string]noDelegate UUIDs; default [].
metricobjectnoMetric configuration.
metric.namestringnoDefaults to Progress.
metric.start_valuenumbernoDefaults to 0.
metric.target_valuenumbernoDefaults to 100.
metric.unitstringnoDefaults to percentage; one of percentage, number, dollar, euro, pound, swiss_franc.
metric.metric_typestringnoDefaults to reach; one of reach, stay_above, stay_below, stay_between.
parentsarray[object]noArray 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_entitiesarray[object]noWho 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}.

FieldTypeDefaultNotes
including_immediate_objectivesbooleanfalseInclude immediate objectives.
including_immediate_initiativesbooleanfalseInclude immediate initiatives.
including_immediate_key_resultsbooleanfalseInclude immediate key results.
delete_hierarchybooleanfalseDelete 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.

MethodPathSummary
GET/rest/v2/labelsList labels and label groups.
POST/rest/v2/labelsCreate 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.

MethodPathSummary
GET/rest/v2/teamsList teams.
POST/rest/v2/teamsCreate 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.

MethodPathSummary
GET/rest/v2/usersList users.
POST/rest/v2/usersCreate 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

CodeMeaning
200Success.
201Created.
400Bad Request — invalid parameters or malformed request.
401Unauthorized — invalid or missing authentication.
403Forbidden — caller lacks permission to access the resource.
404Not Found — resource does not exist.
422Unprocessable Entity — invalid request parameters or validation errors.
429Too Many Requests — rate limit exceeded.
500Internal 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
  • team

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.