Documentation Get help

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.

MethodPathPermission
GET/org/:orgId/custom-attributesView Entity Configuration (settings_entity_config_view)
GET/org/:orgId/custom-attributes/:definitionIdView Entity Configuration (settings_entity_config_view)
POST/org/:orgId/custom-attributesUpdate Entity Configuration (settings_entity_config_update)
PATCH/org/:orgId/custom-attributes/:definitionIdUpdate Entity Configuration (settings_entity_config_update)
DELETE/org/:orgId/custom-attributes/:definitionIdDelete Entity Configuration (settings_entity_config_delete)
GET/org/:orgId/{entity}/:id/custom-attributesView Entity Configuration (settings_entity_config_view)
PUT/org/:orgId/{entity}/:id/custom-attributes/:definitionIdUpdate Entity Configuration (settings_entity_config_update)
DELETE/org/:orgId/{entity}/:id/custom-attributes/:definitionIdUpdate 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

FieldTypeDescription
idstringFlowstate id. Read-only.
namestringDisplay name. Unique per organisation.
attributeKeystringMachine key, e.g. "cost_centre_code". Unique per organisation. Can’t be changed after creation.
fieldTypestringSTRING, NUMBER, DATE, DATE_RANGE, SELECT or CURRENCY.
entityTypesstring[]Records it applies to: EMPLOYEE, CONTRACTOR, VACANCY, TEAM, PROJECT, FUNCTIONAL_GROUP, FUNCTIONAL_POSITION.
descriptionstring | null
isRequiredbooleanWhether the app asks for it when a record is edited.
isActivebooleanInactive definitions are hidden in the app.
sortOrderintegerDisplay order, lowest first.
selectOptionsarray | nullSELECT only: { "key", "label", "color" } per option.
createdAt, updatedAtstringISO 8601. Read-only.

The value object

FieldTypeSet for
idstringFlowstate id. Read-only.
definitionIdstring
entityTypestringEMPLOYEE, CONTRACTOR, VACANCY, TEAM or PROJECT.
entityIdstringThe record’s Flowstate id.
stringValuestring | nullSTRING. Up to 255 characters.
numberValuenumber | nullNUMBER
dateValuestring | nullDATE. ISO 8601.
dateRangeStart, dateRangeEndstring | nullDATE_RANGE. ISO 8601.
selectValuestring | nullSELECT. An option key.
currencyCodestring | nullCURRENCY. ISO 4217, e.g. "GBP".
currencyAmountstring | nullCURRENCY. Decimal string, up to 2 decimal places.
createdAt, updatedAtstringISO 8601. Read-only.
definitionobjectThe 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
ParameterTypeDefaultDescription
pageinteger11-based.
limitinteger201–100.
searchstring—Case-insensitive match on name or description.
entityTypestring—Only definitions that apply to this record type.
sortBystringsortOrdersortOrder, name, createdAt or fieldType.
sortDirstringascasc 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
FieldTypeRequiredDescription
namestringYesUnique per organisation.
fieldTypestringYesSTRING, NUMBER, DATE, DATE_RANGE or CURRENCY.
entityTypesstring[]YesAt least one.
attributeKeystringNo^[a-z][a-z0-9_]*$, up to 100 characters.
descriptionstring | nullNo
isRequiredbooleanNoDefault false.
isActivebooleanNoDefault true.
sortOrderintegerNoDefault 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.

FieldTypeFor
stringValuestring | nullSTRING
numberValuenumber | nullNUMBER
dateValuestring | nullDATE
dateRangeStart, dateRangeEndstring | nullDATE_RANGE
selectValuestring | nullSELECT: an option key from selectOptions.
currencyCodestring | nullCURRENCY: three capital letters.
currencyAmountnumber | nullCURRENCY

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

  1. GET /custom-attributes?entityType=EMPLOYEE and find the definition by attributeKey. Create it if it’s missing.
  2. For each person, PUT /employees/{externalId}/custom-attributes/{definitionId} with the value.
  3. For a person whose field is now empty, DELETE the value.

Functional groups and positions

Values on functional groups and positions are set under the functional groups resource. See Functional groups.

Errors

StatuscodeWhen
400VALIDATION_ERRORA field is invalid (details[].field names it), or name or attributeKey is already used.
400VALIDATION_ERRORThe definition doesn’t apply to the record type: "Custom attribute \"Cost Centre Code\" does not apply to entity type PROJECT. Allowed: EMPLOYEE, CONTRACTOR".
403FORBIDDENThe key lacks the permission in the table above.
404NOT_FOUNDNo such definition ("Custom attribute definition not found: …"), record ("PROJECT not found: …"), or value to delete.

See Errors for the error body.