Rhythms REST API v2

Last updated: September 4, 2026

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.

ParameterTypeDefaultDescription
pagenumber1Page number.
limitnumber20Records per page, maximum 100.
per_pagenumber20Alias for limit.
limit_maxnumberMaximum records per page; used as the page size when limit is not set.
countstringSet 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

curl -H "Authorization: Bearer tokp_1abc23c45d..." \
     -H "Accept: application/json" \
     "https://api.rhythms.ai/rest/v2/objectives?limit=1"

List endpoints return data.records (an array) plus data.pagy:

{
  "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 live docs carry the full schema.

Filtering

List endpoints accept a q parameter using bracket notation: the attribute name followed by a predicate.

PredicateMeaning
_eqexact match
_contcontains (substring)
_invalue is in a list, e.g. q[current_status_in][]=behind&q[current_status_in][]=at_risk
_gteq / _lteqgreater than or equal / less than or equal — useful on dates
_present / _nullattribute is set / attribute is null
# objectives that have not started
GET /rest/v2/objectives?q[current_status_eq]=not_started

# check-ins since 1 July 2026
GET /rest/v2/checkins?q[checkin_date_gteq]=2026-07-01

# users whose display name contains "Alice"
GET /rest/v2/users?q[display_name_cont]=Alice

# labels that are groups, sorted by name
GET /rest/v2/labels?q[is_group_eq]=true&q[s]=name+asc

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

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.

When authentication fails

A missing or invalid token returns 401:

{ "error": "Invalid Authorization header" }

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.

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

FieldTypeRequiredNotes
goal_uuidstringyesUUID of the goal being checked in. (checkinable_uuid is accepted as a deprecated alias.)
timezone_offsetnumberyesYour offset from UTC in minutes, as JavaScript's getTimezoneOffset() reports it (negative east of UTC). Must be between -840 and 720.
valuenumbernoCheck-in value. The goal must have a metric.
statusstringnoDefaults to not_started; one of not_started, in_progress, on_track, behind, at_risk, closed, postponed.
notestringnoCheck-in note.
checkin_datestringnoYYYY-MM-DD. Defaults to today in your timezone; cannot be in the future.
scorenumbernoScore; only stored when status is closed.
progress_modestringnoSets the goal's progress mode: manual, rollup or integration.
labelsarray[string]noLabel 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} updates value, status, note, score and labels. At least one must be provided. A score is kept only while the status is closed.
  • 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

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}

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

FieldTypeRequiredNotes
titlestringyesGoal title.
descriptionstringnoGoal description.
time_period_uuidstringyesTime period UUID. Its dates define the allowed goal date range.
start_datestringnoYYYY-MM-DD; must fall within the time period and be on or before end_date. Defaults to the period start.
end_datestringnoYYYY-MM-DD; must fall within the time period and be on or after start_date. Defaults to the period end.
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 []. Unknown names are created when the token's user may create labels.
delegate_uuidsarray[string]noDelegate UUIDs; default [].
metricobjectnoMetric configuration.
metric.namestringnoDefaults to Progress.
metric.start_valuenumbernoDefaults to 0.
metric.target_valuenumbernoDefaults to 100.
metric.unitstringnoOne 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_typestringnoDefaults to reach; one of reach, stay_above, stay_below, stay_between.
parentsarray[object]noParent 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_entitiesarray[object]noWho 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.

FieldTypeDefaultNotes
including_immediate_objectivesbooleanfalseAlso delete immediate child objectives.
including_immediate_initiativesbooleanfalseAlso delete immediate child initiatives.
including_immediate_key_resultsbooleanfalseAlso delete immediate child key results.
delete_hierarchybooleanfalseDelete 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.

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

MethodPathSummary
GET/rest/v2/teamsList teams.
POST/rest/v2/teamsCreate 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_uuids and member_uuids. A user listed in both arrays becomes a Team Owner.
  • Update accepts the same fields plus status, one of active or archived. Status can only be set on update, not on create. Sending owner_uuids replaces the full set of Team Owners; sending member_uuids adds 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.

MethodPathSummary
GET/rest/v2/usersList users.
POST/rest/v2/usersCreate 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) and display_name. Optional: license_type (standard, hris_only or guest; default standard), status (active or closed; default active), manager_uuid, and profile_attributes with first_name, last_name, job_title, timezone, locale and about.
  • Update accepts display_name, avatar_url (applied only when the user has no avatar yet), status, manager_uuid, license_type and profile_attributes.

A manager_uuid must refer to an existing user, otherwise the request returns 422.

Common response codes

CodeMeaning
200Success.
201Created.
400Bad Request — invalid parameters or malformed request.
401Unauthorized — invalid or missing token, or the token's user is no longer active.
403Forbidden — the token's user is not allowed to perform this action in Rhythms.
404Not Found — resource does not exist.
422Unprocessable Entity — validation error; the body explains which rule failed.
429Too Many Requests — back off and retry.
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 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