Custom attributes
A custom attribute is a field your organisation adds to a record: a cost centre code, a pay band, a compliance date. A definition says what the field is and which records it applies to. A value is that field’s data on one record.
All paths are under https://{tenant}.flowstate.inc/api/v1. Custom attributes are live data; scenarioId is ignored.
| Method | Path | Permission |
|---|---|---|
GET | /org/:orgId/custom-attributes | View Entity Configuration (settings_entity_config_view) |
GET | /org/:orgId/custom-attributes/:definitionId | View Entity Configuration (settings_entity_config_view) |
POST | /org/:orgId/custom-attributes | Update Entity Configuration (settings_entity_config_update) |
PATCH | /org/:orgId/custom-attributes/:definitionId | Update Entity Configuration (settings_entity_config_update) |
DELETE | /org/:orgId/custom-attributes/:definitionId | Delete Entity Configuration (settings_entity_config_delete) |
GET | /org/:orgId/{entity}/:id/custom-attributes | View Entity Configuration (settings_entity_config_view) |
PUT | /org/:orgId/{entity}/:id/custom-attributes/:definitionId | Update Entity Configuration (settings_entity_config_update) |
DELETE | /org/:orgId/{entity}/:id/custom-attributes/:definitionId | Update Entity Configuration (settings_entity_config_update) |
{entity} is employees, contractors, vacancies, teams or projects. There :id accepts a Flowstate id or the record’s externalId. :definitionId is always the definition’s Flowstate id.
Definitions are also managed in the app at Settings → Resourcing → Custom Attributes.
The definition object
| Field | Type | Description |
|---|---|---|
id | string | Flowstate id. Read-only. |
name | string | Display name. Unique per organisation. |
attributeKey | string | Machine key, e.g. "cost_centre_code". Unique per organisation. Can’t be changed after creation. |
fieldType | string | STRING, NUMBER, DATE, DATE_RANGE, SELECT or CURRENCY. |
entityTypes | string[] | Records it applies to: EMPLOYEE, CONTRACTOR, VACANCY, TEAM, PROJECT, FUNCTIONAL_GROUP, FUNCTIONAL_POSITION. |
description | string | null | |
isRequired | boolean | Whether the app asks for it when a record is edited. |
isActive | boolean | Inactive definitions are hidden in the app. |
sortOrder | integer | Display order, lowest first. |
selectOptions | array | null | SELECT only: { "key", "label", "color" } per option. |
createdAt, updatedAt | string | ISO 8601. Read-only. |
The value object
| Field | Type | Set for |
|---|---|---|
id | string | Flowstate id. Read-only. |
definitionId | string | |
entityType | string | EMPLOYEE, CONTRACTOR, VACANCY, TEAM or PROJECT. |
entityId | string | The record’s Flowstate id. |
stringValue | string | null | STRING. Up to 255 characters. |
numberValue | number | null | NUMBER |
dateValue | string | null | DATE. ISO 8601. |
dateRangeStart, dateRangeEnd | string | null | DATE_RANGE. ISO 8601. |
selectValue | string | null | SELECT. An option key. |
currencyCode | string | null | CURRENCY. ISO 4217, e.g. "GBP". |
currencyAmount | string | null | CURRENCY. Decimal string, up to 2 decimal places. |
createdAt, updatedAt | string | ISO 8601. Read-only. |
definition | object | The definition object. |
GET /{entity}/:id on employees, contractors, vacancies, teams and projects includes the record’s values as customAttributes, so you rarely need the value list endpoint.
List definitions
GET /org/:orgId/custom-attributes
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | 1-based. |
limit | integer | 20 | 1–100. |
search | string | — | Case-insensitive match on name or description. |
entityType | string | — | Only definitions that apply to this record type. |
sortBy | string | sortOrder | sortOrder, name, createdAt or fieldType. |
sortDir | string | asc | asc or desc. |
curl "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/custom-attributes?entityType=EMPLOYEE&limit=100" \
-H "Authorization: Bearer private_..."
{
"data": [
{
"id": "clx2d3e4f5g6h7i8j9k0l1m2n",
"name": "Cost Centre Code",
"attributeKey": "cost_centre_code",
"fieldType": "STRING",
"entityTypes": ["EMPLOYEE", "CONTRACTOR"],
"description": "Finance cost centre code.",
"isRequired": false,
"isActive": true,
"sortOrder": 0,
"selectOptions": null,
"createdAt": "2026-03-01T10:00:00.000Z",
"updatedAt": "2026-03-01T10:00:00.000Z"
}
],
"meta": { "page": 1, "limit": 100, "total": 1, "hasNextPage": false }
}
Retrieve a definition
GET /org/:orgId/custom-attributes/:definitionId
Returns the definition object.
Create a definition
POST /org/:orgId/custom-attributes
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Unique per organisation. |
fieldType | string | Yes | STRING, NUMBER, DATE, DATE_RANGE or CURRENCY. |
entityTypes | string[] | Yes | At least one. |
attributeKey | string | No | ^[a-z][a-z0-9_]*$, up to 100 characters. |
description | string | null | No | |
isRequired | boolean | No | Default false. |
isActive | boolean | No | Default true. |
sortOrder | integer | No | Default 0. |
Without attributeKey, one is made from name: accents dropped, lower-cased, every run of other characters replaced by _. "Cost Centre Code" becomes cost_centre_code. If that key is taken, _2, _3 and so on is added.
Create SELECT attributes in the app, where their options are set.
curl -X POST "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/custom-attributes" \
-H "Authorization: Bearer private_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Cost Centre Code",
"fieldType": "STRING",
"entityTypes": ["EMPLOYEE", "CONTRACTOR"],
"description": "Finance cost centre code."
}'
201 Created with the definition object.
Update a definition
PATCH /org/:orgId/custom-attributes/:definitionId
Takes name, entityTypes, description, isRequired, isActive and sortOrder, all optional. attributeKey is ignored.
curl -X PATCH "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/custom-attributes/clx2d3e4f5g6h7i8j9k0l1m2n" \
-H "Authorization: Bearer private_..." \
-H "Content-Type: application/json" \
-d '{ "isRequired": true, "entityTypes": ["EMPLOYEE", "CONTRACTOR", "VACANCY"] }'
200 OK with the updated definition.
Delete a definition
DELETE /org/:orgId/custom-attributes/:definitionId
Deletes the definition and every value set with it, on every record. This can’t be undone.
{ "data": { "id": "clx2d3e4f5g6h7i8j9k0l1m2n", "deleted": true } }
List a record’s values
GET /org/:orgId/{entity}/:id/custom-attributes
Returns every value on the record, in definition sortOrder. Not paginated.
curl "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/employees/HR-10442/custom-attributes" \
-H "Authorization: Bearer private_..."
{
"data": [
{
"id": "clx8v9w0x1y2z3a4b5c6d7e8f",
"definitionId": "clx2d3e4f5g6h7i8j9k0l1m2n",
"entityType": "EMPLOYEE",
"entityId": "clx1a2b3c4d5e6f7g8h9i0j1k",
"stringValue": "ENG-001",
"numberValue": null,
"dateValue": null,
"dateRangeStart": null,
"dateRangeEnd": null,
"selectValue": null,
"currencyCode": null,
"currencyAmount": null,
"createdAt": "2026-04-08T10:00:00.000Z",
"updatedAt": "2026-04-08T10:00:00.000Z",
"definition": {
"id": "clx2d3e4f5g6h7i8j9k0l1m2n",
"name": "Cost Centre Code",
"attributeKey": "cost_centre_code",
"fieldType": "STRING",
"entityTypes": ["EMPLOYEE", "CONTRACTOR"],
"description": "Finance cost centre code.",
"isRequired": false,
"isActive": true,
"sortOrder": 0,
"selectOptions": null,
"createdAt": "2026-03-01T10:00:00.000Z",
"updatedAt": "2026-03-01T10:00:00.000Z"
}
}
]
}
Set a value
PUT /org/:orgId/{entity}/:id/custom-attributes/:definitionId
Creates the value or replaces it. Send the fields for the definition’s fieldType; every value field you leave out is cleared.
| Field | Type | For |
|---|---|---|
stringValue | string | null | STRING |
numberValue | number | null | NUMBER |
dateValue | string | null | DATE |
dateRangeStart, dateRangeEnd | string | null | DATE_RANGE |
selectValue | string | null | SELECT: an option key from selectOptions. |
currencyCode | string | null | CURRENCY: three capital letters. |
currencyAmount | number | null | CURRENCY |
The definition’s entityTypes must include the record’s type.
curl -X PUT "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/projects/JIRA-MOB/custom-attributes/clx4f5g6h7i8j9k0l1m2n3o4p" \
-H "Authorization: Bearer private_..." \
-H "Content-Type: application/json" \
-d '{ "currencyCode": "GBP", "currencyAmount": 125000 }'
200 OK with the value object.
Clear a value
DELETE /org/:orgId/{entity}/:id/custom-attributes/:definitionId
{ "data": { "definitionId": "clx2d3e4f5g6h7i8j9k0l1m2n", "entityId": "clx1a2b3c4d5e6f7g8h9i0j1k", "deleted": true } }
Sync a field from your HR system
GET /custom-attributes?entityType=EMPLOYEEand find the definition byattributeKey. Create it if it’s missing.- For each person,
PUT /employees/{externalId}/custom-attributes/{definitionId}with the value. - For a person whose field is now empty,
DELETEthe value.
Functional groups and positions
Values on functional groups and positions are set under the functional groups resource. See Functional groups.
Errors
| Status | code | When |
|---|---|---|
400 | VALIDATION_ERROR | A field is invalid (details[].field names it), or name or attributeKey is already used. |
400 | VALIDATION_ERROR | The definition doesn’t apply to the record type: "Custom attribute \"Cost Centre Code\" does not apply to entity type PROJECT. Allowed: EMPLOYEE, CONTRACTOR". |
403 | FORBIDDEN | The key lacks the permission in the table above. |
404 | NOT_FOUND | No such definition ("Custom attribute definition not found: …"), record ("PROJECT not found: …"), or value to delete. |
See Errors for the error body.