Object-based endpoints

Learn about the new object-based endpoints in our public API

Introduction

We're gradually moving toward a new model for our Public API, one that's object-based, where each object has a clear structure, predictable references, and its own metadata.

This article explains the key ideas behind this model, how the data is structured, and what to expect when working with these endpoints.

Standardizing how object data is exposed allows:

  • A consistent field structure
  • Predictable reference behavior
  • Support for customization and localization
  • A scalable approach to bulk reads and writes

Important notes:

  • To support a gradual shift to the object-based model, some objects, like Positions, may have both legacy and object-based endpoints under /v1.
  • For example, a search endpoint may return data in the legacy format, while newly introduced create and update endpoints for the same object follow the object-based structure.
  • The underlying field IDs and other metadata fields will remain consistent to ensure smooth usage with both approaches.

Key principles

These are the key principles of the object-based approach:

  • All object data lives under theitems array:
    • Simple fields (text, numbers, enums) return a primitive value, and may return a display value (e.g. for enums).
    • Reference and object fields return structured data or the ID of the sub-object.
  • Endpoint URLs include the module name and the resource name. For example: goals/goal-types
  • Metadata endpoints tell you what fields are available and how to use them. You’re expected to build requests dynamically using metadata (rather than hardcoding field names), especially as object definitions become customizable.
  • Reference fields by default, reference to other objects return only the ID. One-to-one references may return full objects; one-to-many data is exposed via separate endpoints.
  • Search endpoints use POST with a consistent structure for fields, filters, and pagination.

Note: Not all endpoints currently enforce pagination. You’ll find a note in each API's documentation that clearly states whether pagination is currently enforced.

  • Human-readable values are included in the response when relevant, for example, when the value is an item in a list.
  • Access control is built-in. Fields that the service user isn’t authorized to access are automatically excluded from results. If the whole object cannot be accessed, a permissions/authorization error is returned.
  • PATCH is the standard for updates; PUT is used rarely and only for full replacements.

Object-based payload example

{
  "items": [
    {
      "objectType": "goal",
      "fields": {
        "id": {
          "value": 1
        },
        "title": {
          "value": "Sample Title 1"
        },
        "description": {
          "value": "Sample description"
        },
        "startDate": {
          "value": "2025-01-01"
        },
        "dueDate": {
          "value": "2025-10-10"
        },
        "typeId": {
          "value": 9292
        },
        "category": {
          "value": "Company"
        },
        "status": {
          "value": "completed"
        },
        "owner": {
          "value": 123123123
        },
        "isPrivate": {
          "value": false
        },
        "alignedGoal": {
          "value": 9797
        },
        "hasKeyResults": {
          "value": true
        },
        "isActive": {
          "value": false
        }
      }
    }
  ],
  "responseMetadata": {
    "totalCount": 0,
    "pageSize": 0
  },
  "nextCursor": "string",
  "errors": {}
}

Metadata

Each object includes a metadata endpoint that describes its fields and their types. This helps to dynamically understand how to interpret and display object data.

Metadata endpoints are placed under the object’s base path, for example: /goals/goal-types/metadata

A standard format for metadata responses is returned for object-based entities.

Metadata response:

{
  "items": [
    {
      "id": "goal",
      "displayName": "The Goal Object",
      "fields": [
        {
          "id": "id",
          "type": {
            "dataType": "number"
          },
          "propertiesValues": {
            "isRequired": {
              "value": false
            },
            "displayName": {
              "value": "ID"
            },
            "description": {
              "value": "The unique identifier for the goal"
            }
          }
        },
        {
          "id": "title",
          "type": {
            "dataType": "string"
          },
          "propertiesValues": {
            "isRequired": {
              "value": false
            },
            "displayName": {
              "value": "Title"
            },
            "description": {
              "value": "The title of the goal"
            }
          }
        }
      ]
    }
  ]
}

Referencing to other objects

Reference fields are used to connect objects together. Depending on the type, the data returned may vary:

TypeReturned DataExample
Enum or simple referenceJust the ID"id": { "value": "123" }
One-to-one sub-objectFull object with fieldsbudget in a goal
One-to-many sub-objectsUse relevant endpointsget goal's key results

Note: Historical data and 1-to-many relationships are not embedded but exposed via separate endpoints.