Beta notice
Productboard REST API 2.0 is currently in Beta. Use it for experimentation, prototyping, and early integrations. Please note that individual endpoints may still change before the public release. We’re actively looking for Feedback & Help – let us know what works and what doesn’t. For critical production systems, continue using the Productboard REST API v1.0.
Why use the configuration endpoint?
The configuration endpoint provides a way to programmatically access and manage the configuration settings of your Productboard workspace. The API provides 2 configuration endpoints:
The configuration endpoint is a critical part of the Productboard API. Productboard provides a flexible data model and the API allows users to interact with this model in a programmatic way.
In a "traditional" API, you might have fixed responses for specific endpoints. For example, a GET /entities?type=feature endpoint might return a list of features with predefined fields like id, name, and status. This allows for a straightforward interaction with the API, but it can be limiting when the underlying data model is flexible and customizable.
In a "configuration-driven" API like Productboard's, the structure of the data returned by the API can change based on the configuration of the workspace. Taking the same example, to interact with the GET /entities?type=feature endpoint, we first have to call the configuration endpoint to understand what fields are available for features in the current workspace. The configuration endpoint will return a list of fields, their types, and other metadata. This allows clients to dynamically adapt to the structure of the data.
The basic structure of the configuration response
The configuration response typically includes the following elements:
type: The type of entity being configured- For example, for notes configuration,
"type": "simple" - For example, for entities configuration,
"type": "feature"
- For example, for notes configuration,
fields: A list of fields available for the entity, including their names, types, constraints, and a list of operations that can be performed on the field
Working with fields
Fields are the building blocks of the configuration endpoint. Each field has a set of properties that define its characteristics and behavior. Here are some common properties you might encounter:
id: A unique identifier for the fieldname: The name of the field. This is the name users will see within the Productboard UI.schema: The data type of the fieldconstraints: Any constraints that apply to the field, such as whether it is required or whether there are length limitslifecycle: this determines the operations that can be performed on the field.
Example field definition
Assume we called the configuration endpoint for the feature entity type. In the example below, we can determine:
- The
idisname - The
nameisName- This is the field name that will be displayed in the Productboard UI
- The
schemaisTextFieldValue- This indicates that the field is a text field, and can be mapped to a string in your code
- The field is
required- This means that when creating or updating a feature, a value for this field must be provided
- You can also reasonably assume that this field will always be present when retrieving a feature
- The field has a
maxLengthconstraint of 255 characters- This can be used for validation when working with this field
"fields": {
"name": {
"id": "name",
"name": "Name",
"path": "/fields/name",
"schema": "TextFieldValue",
"lifecycle": {
"create": {
"set": true
},
"update": {
"set": true
},
"patch": {
"set": true
}
},
"constraints": {
"required": true,
"maxLength": 255
},
"links": {
"self": null
}
}
}Understanding field lifecycle
The lifecycle property of a field defines the operations that can be performed on that field. The lifecycle object can contain the following properties:
create- Operations allowed when creating a fieldupdate- Operations allowed when updating a field using the simpledata.fieldsapproachpatch- Operations allowed when updating a field using JSON Patch arrays viadata.patch
The difference between update and patch
Both update and patch are used for modifying existing entities, but they differ in how you structure the request:
Update uses the simpler data.fields approach where you send field updates directly in a fields object:
{
"data": {
"fields": {
"name": "Hello World"
}
}
}Patch uses a JSON Patch-like syntax (inspired by RFC 6902) where you send updates as an array of operations via data.patch:
{
"data": {
"patch": [
{ "op": "set", "path": "name", "value": "Hello World" }
]
}
}The lifecycle configuration tells you which approach is allowed for each field and what operations (set, clear, addItems, removeItems) are supported with each approach. Note that the op values in the patch array correspond directly to the lifecycle operations (set, clear, addItems, removeItems), not the standard JSON Patch operations.
Each of these properties (create, update, patch) can contain a list of operations that are allowed for that field. If the operation is allowed, it will be set to true. The operations are:
set- Allows setting the value of the fieldclear- Allows clearing the value of the fieldaddItems- Allows adding items to an array fieldremoveItems- Allows removing items from an array field
Example lifecycle definition
Assume we called the configuration endpoint for the feature entity type. In the example below, we can determine that:
- When we
create,update, orpatcha feature, we cansetthe value of theownerfield. - When we
updateorpatcha feature, we can alsoclearthe value of theownerfield.
"fields": {
"owner": {
"id": "owner",
"name": "Owner",
"path": "/fields/owner",
"schema": "MemberFieldValue",
"lifecycle": {
"create": {
"set": true
},
"update": {
"set": true,
"clear": true
},
"patch": {
"set": true,
"clear": true
}
},
"links": {
"self": null
}
}
}Combining configuration data with other endpoints
A typical workflow when using the configuration endpoint involves the following steps:
- Call the configuration endpoint to retrieve the current configuration settings for the desired entity type (e.g., features, notes, etc.)
- Parse the configuration response to understand the available fields, their types, and the operations that can be performed on them
- It might be useful to build classes or data structures in your code to represent the configuration data. For example, you might create a
Fieldclass that encapsulates the properties of a field and provides methods for interacting with it.
- It might be useful to build classes or data structures in your code to represent the configuration data. For example, you might create a
- Make a request to an endpoint that you have a configuration for. For example, if you have the configuration for features, you might make a request to
GET /entities?type=featureto retrieve a list of features.- If you're retrieving data, you can validate the response against the data types defined in the configuration.
- If you're creating, deleting, or updating data, you can ensure that the data you're sending conforms to the constraints and operations defined in the configuration.
Example: Features export
In the Features export recipe, we demonstrate how to use the configuration endpoint to dynamically adapt to the structure of features in a Productboard workspace. The recipe involves:
- In the function
def fetch_configuration(entity_type), we call the configuration endpoint to retrieve the configuration for features. - In the function
def generate_csv(configuration, entities, output_file), we use the configuration data to determine which fields to include in the CSV header row.
The advantage of this approach is that if the configuration of features changes (e.g., new fields are added, existing fields are removed), the export functionality will automatically adapt to these changes without requiring hardcoded field definitions.
