Skip to content

Employees

Manage employee records in your organization. Employees represent full-time and part-time staff with salary information, team memberships, and project assignments.

New to Flowstate?

Read the Domain Model first to understand how employees relate to teams, projects, salary adjustments, and assignments.

Employee Object

The employee object represents a single person employed by your organization.

FieldTypeDescription
idstringUnique identifier for the employee (CUID format, e.g. clx1a2b3c4d5e6f7g8h9). System-generated. Read-only.
externalIdstring | nullYour external identifier for this employee. Unique within your organization. Use for lookups via path parameters.
firstNamestringEmployee's first (given) name.
lastNamestringEmployee's last (family) name.
emailstringWork email address. Must be unique within the organization.
internalEmployeeIdstring | nullYour organization's internal employee/HR identifier (e.g. from BambooHR or Workday).
startDatedate (YYYY-MM-DD)Employment start date. Used for headcount forecasting and cost calculations.
endDatedate (YYYY-MM-DD) | nullEmployment end date. null means the employee is currently active.
noticeDatedate (YYYY-MM-DD) | nullDate the employee gave notice. Distinct from endDate -- notice triggers forecast adjustments before the actual departure.
managerIdstring | nullID of the employee's direct manager. References another employee in this organization.
jobRoleIdstring | nullID of the employee's job role (e.g. "Senior Engineer"). Use GET /job-roles to list valid values.
workTypeIdstring | nullWork arrangement classification (e.g. full-time, part-time). References a Work Type.
geographyIdstring | nullEmployee's work location/region. References a Location. Affects currency defaults and cost multipliers.
defaultCurrencyCodestring | nullISO 4217 currency code (e.g. GBP, USD). If not set, defaults to the geography's currency.
createdAtdatetime (ISO 8601)When the record was created. Read-only.
updatedAtdatetime (ISO 8601)When the record was last modified. Read-only.
customAttributesarrayCustom attribute values for this employee. Returned on GET-by-ID. See Custom Attributes.

Endpoints

MethodPathDescription
GET/org/:orgId/employeesList employees
GET/org/:orgId/employees/:idGet employee
POST/org/:orgId/employeesCreate employee
PATCH/org/:orgId/employees/:idUpdate employee
DELETE/org/:orgId/employees/:idDelete employee

External ID Support

The :id path parameter accepts either a Flowstate CUID (e.g. clx1a2b3c4d5e6f7g8h9) or your externalId. The format is auto-detected — CUIDs are 25-character lowercase alphanumeric strings starting with a letter; anything else is treated as an external ID lookup.


List Employees

GET /org/:orgId/employees

Returns a paginated list of employees in the organization.

Query Parameters

ParameterTypeDefaultDescription
pageinteger1Page number (1-based).
limitinteger20Records per page. Min 1, max 100.
searchstring--Free-text search across first name, last name, and email.
sortBystringlastNameField to sort by (e.g. lastName, startDate, email).
sortDirstringascSort direction: asc or desc.
scenarioIdstring--Scenario ID for what-if queries. Omit for live data.

Example Request

bash
curl -X GET "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/employees?sortBy=lastName&limit=10" \
  -H "Authorization: Bearer private_..."

Example Response

json
{
  "data": [
    {
      "id": "clx1a2b3c4d5e6f7g8h9",
      "externalId": "EMP-1042",
      "firstName": "Jane",
      "lastName": "Chen",
      "email": "jane.chen@example.com",
      "internalEmployeeId": "EMP-1042",
      "startDate": "2024-03-15",
      "endDate": null,
      "noticeDate": null,
      "managerId": "clx9m4n5o6p7q8r9",
      "jobRoleId": "clx9r8q7w6e5t4r3",
      "workTypeId": "clx2w3x4y5z6a7b8",
      "geographyId": "clx3g2h1j0k9l8m7",
      "defaultCurrencyCode": "USD",
      "createdAt": "2024-03-15T10:30:00Z",
      "updatedAt": "2024-06-01T14:22:00Z"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 10,
    "total": 142,
    "hasNextPage": true
  }
}

Get Employee

GET /org/:orgId/employees/:id

Returns a single employee by ID.

Use the include query parameter to embed related data in the response. Pass a comma-separated list of include keys:

Include KeyDescription
currentSalaryThe employee's current salary adjustment (most recent by effectiveDate).
salaryHistoryAll salary adjustments for the employee, ordered by effectiveDate descending.
assignmentsAll active team and project assignments for the employee.
GET /org/:orgId/employees/:id?include=currentSalary,assignments

Example Request

bash
curl -X GET "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/employees/clx1a2b3c4d5e6f7g8h9?include=currentSalary,assignments" \
  -H "Authorization: Bearer private_..."

Example Response

json
{
  "data": {
    "id": "clx1a2b3c4d5e6f7g8h9",
    "externalId": "EMP-1042",
    "firstName": "Jane",
    "lastName": "Chen",
    "email": "jane.chen@example.com",
    "internalEmployeeId": "EMP-1042",
    "startDate": "2024-03-15",
    "endDate": null,
    "noticeDate": null,
    "managerId": "clx9m4n5o6p7q8r9",
    "jobRoleId": "clx9r8q7w6e5t4r3",
    "workTypeId": "clx2w3x4y5z6a7b8",
    "geographyId": "clx3g2h1j0k9l8m7",
    "defaultCurrencyCode": "USD",
    "createdAt": "2024-03-15T10:30:00Z",
    "updatedAt": "2024-06-01T14:22:00Z",
    "customAttributes": [
      {
        "id": "clx8v9w0x1y2z3a4b5c6",
        "definitionId": "clx2d3e4f5g6h7i8j9k0",
        "entityType": "EMPLOYEE",
        "entityId": "clx1a2b3c4d5e6f7g8h9",
        "stringValue": "ENG-001",
        "numberValue": null,
        "dateValue": null,
        "dateRangeStart": null,
        "dateRangeEnd": null,
        "definition": {
          "id": "clx2d3e4f5g6h7i8j9k0",
          "name": "Cost Centre Code",
          "attributeKey": "cost_centre_code",
          "fieldType": "STRING"
        }
      }
    ],
    "currentSalary": {
      "id": "clx5s6a7l8r9y0j1",
      "employeeId": "clx1a2b3c4d5e6f7g8h9",
      "effectiveDate": "2026-01-01",
      "salary": 95000,
      "bonus": 10000,
      "currencyCode": "USD",
      "reason": "Annual review",
      "createdAt": "2025-12-15T10:30:00Z",
      "updatedAt": "2025-12-15T10:30:00Z"
    },
    "assignments": [
      {
        "id": "clx8a9b0c1d2e3f4",
        "type": "team",
        "targetId": "clx6t7u8v9w0x1y2",
        "fte": 0.6,
        "startDate": "2025-01-01",
        "endDate": null,
        "createdAt": "2024-12-15T10:00:00Z",
        "updatedAt": "2025-06-01T14:00:00Z"
      },
      {
        "id": "clx9b0c1d2e3f4g5",
        "type": "project",
        "targetId": "clx7p8r9q0s1t2u3",
        "fte": 0.4,
        "startDate": "2025-03-01",
        "endDate": "2025-12-31",
        "createdAt": "2025-02-20T09:00:00Z",
        "updatedAt": "2025-02-20T09:00:00Z"
      }
    ]
  }
}

About included assignments

Each assignment in the assignments array contains type ("team" or "project") and targetId (the ID of the team or project). See Assignments for full details.


Create Employee

POST /org/:orgId/employees

Creates a new employee record. You can optionally include nested objects to atomically create a salary adjustment, team assignment, and/or project assignment in the same request.

Create Request Body

FieldTypeRequiredDescription
firstNamestringYesEmployee's first (given) name.
lastNamestringYesEmployee's last (family) name.
emailstringYesWork email address. Must be a valid email and unique within the organization.
internalEmployeeIdstring | nullNoYour internal HR identifier (e.g. "EMP-2001").
externalIdstring | nullNoYour external identifier for this employee. Must be unique within the organization. Cannot resemble a CUID format. Max 255 characters.
startDatedate (YYYY-MM-DD)YesEmployment start date.
endDatedate (YYYY-MM-DD) | nullNoEmployment end date. null or omit for currently active.
noticeDatedate (YYYY-MM-DD) | nullNoDate notice was given.
managerIdstring | nullNoID of an existing employee who is the direct manager.
jobRoleIdstring | nullNoJob role ID. Use GET /job-roles for valid values. Takes precedence over jobRole.
jobRoleobjectNoResolve-or-create a job role by externalId or title. Ignored when jobRoleId is supplied. See below.
workTypeIdstring | nullNoWork Type ID.
geographyIdstring | nullNoLocation ID.
defaultCurrencyCodestring | nullNoISO 4217 currency code (3 uppercase letters, e.g. "GBP").
salaryobjectNoNested salary adjustment to create atomically. See below.
teamAssignmentobjectNoNested team assignment to create atomically. See below.
projectAssignmentobjectNoNested project assignment to create atomically. See below.

Nested jobRole Object

Resolves a job role by external reference, creating it on the fly when the name is new. Match order: externalIdtitle → create. Supply at least one of the two fields.

FieldTypeRequiredDescription
titlestringConditionalHuman-readable role name (e.g. "Senior Engineer"). Required when the externalId doesn't match an existing row — we auto-create by name.
externalIdstringConditionalYour external system's identifier for the role. Preferred match key when supplied. An existing row matched by title will be stamped with this externalId on first contact.

INFO

Sending jobRole: { "externalId": "R-042" } alone with no existing match returns 404 NOT_FOUND — auto-create needs a human-readable title so Flowstate never invents a role name.

Nested salary Object

Creates an initial salary adjustment record for the employee.

FieldTypeRequiredDescription
effectiveDatedate (YYYY-MM-DD)YesDate this salary takes effect. Usually matches the employee's startDate.
salarynumberYesAnnual base salary. Must be >= 0.
currencyCodestringYesISO 4217 currency code (e.g. "GBP").
bonusnumber | nullNoAnnual bonus amount. Must be >= 0. null = no bonus.
reasonstring | nullNoReason (e.g. "Starting salary").

Nested teamAssignment Object

Assigns the employee to a team.

FieldTypeRequiredDescription
teamIdstringYesID of the team to assign the employee to.
ftenumberYesFTE allocation (0.0--10.0). 1.0 = full-time on this team.
startDatedate (YYYY-MM-DD)YesAssignment start date.
endDatedate (YYYY-MM-DD) | nullNoAssignment end date. null = ongoing.
rolestring | nullNoRole within this assignment (e.g. "Tech Lead").

Nested projectAssignment Object

Assigns the employee to a project.

FieldTypeRequiredDescription
projectIdstringYesID of the project to assign the employee to.
ftenumberYesFTE allocation (0.0--10.0).
startDatedate (YYYY-MM-DD)YesAssignment start date.
endDatedate (YYYY-MM-DD) | nullNoAssignment end date. null = ongoing.
rolestring | nullNoRole within this assignment.

Example: Simple Create

bash
curl -X POST "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/employees" \
  -H "Authorization: Bearer private_..." \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Alex",
    "lastName": "Rivera",
    "email": "alex.rivera@example.com",
    "startDate": "2026-07-01",
    "defaultCurrencyCode": "GBP"
  }'

Example: Create with Auto-Created Job Role

Supply jobRole to look up or create the role by external reference, without needing to pre-provision it:

bash
curl -X POST "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/employees" \
  -H "Authorization: Bearer private_..." \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Alex",
    "lastName": "Rivera",
    "email": "alex.rivera@example.com",
    "startDate": "2026-07-01",
    "jobRole": {
      "title": "Senior Engineer",
      "externalId": "ROLE-042"
    }
  }'

If a job role named "Senior Engineer" already exists in the organization, it is reused and stamped with externalId: "ROLE-042" on first contact. Otherwise a new role is created with both fields populated.

Example: Nested Create (Employee + Salary + Team)

This creates the employee, their starting salary, and a team assignment in a single atomic operation:

bash
curl -X POST "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/employees" \
  -H "Authorization: Bearer private_..." \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Alex",
    "lastName": "Rivera",
    "email": "alex.rivera@example.com",
    "externalId": "EMP-2001",
    "startDate": "2026-07-01",
    "geographyId": "clx3g2h1j0k9l8m7",
    "workTypeId": "clx2w3x4y5z6a7b8",
    "jobRoleId": "clx9r8q7w6e5t4r3",
    "managerId": "clx9m4n5o6p7q8r9",
    "salary": {
      "effectiveDate": "2026-07-01",
      "salary": 85000,
      "currencyCode": "GBP",
      "reason": "Starting salary"
    },
    "teamAssignment": {
      "teamId": "clx6t7u8v9w0x1y2",
      "fte": 1.0,
      "startDate": "2026-07-01"
    }
  }'

Example Response

json
{
  "data": {
    "id": "clx7n8m9k0j1h2g3f4e5",
    "externalId": "EMP-2001",
    "firstName": "Alex",
    "lastName": "Rivera",
    "email": "alex.rivera@example.com",
    "internalEmployeeId": null,
    "startDate": "2026-07-01",
    "endDate": null,
    "noticeDate": null,
    "managerId": "clx9m4n5o6p7q8r9",
    "jobRoleId": "clx9r8q7w6e5t4r3",
    "workTypeId": "clx2w3x4y5z6a7b8",
    "geographyId": "clx3g2h1j0k9l8m7",
    "defaultCurrencyCode": null,
    "createdAt": "2026-04-08T09:15:00Z",
    "updatedAt": "2026-04-08T09:15:00Z"
  }
}

Status: 201 Created

TIP

When you provide a geographyId, the employee inherits the location's default currency. You only need to set defaultCurrencyCode explicitly if you want to override the geography's default.


Update Employee

PATCH /org/:orgId/employees/:id

Updates one or more fields on an existing employee. Only include the fields you want to change.

You can also pass salary, teamAssignment, or projectAssignment nested objects on update. These are additive -- they create new records and never overwrite or end existing ones.

Update Request Body

All fields from the Create Request Body are accepted, and all are optional. Additionally:

  • Set endDate to null to clear a previously set departure date.
  • Set noticeDate to null to clear a previously set notice.
  • Set externalId to assign or change the employee's external identifier, or null to clear it.
  • Pass salary to add a new salary adjustment (does not modify existing adjustments).
  • Pass teamAssignment to add a new team assignment (does not end existing assignments).

Example Request

bash
curl -X PATCH "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/employees/clx1a2b3c4d5e6f7g8h9" \
  -H "Authorization: Bearer private_..." \
  -H "Content-Type: application/json" \
  -d '{
    "lastName": "Chen-Rivera",
    "endDate": "2026-12-31",
    "noticeDate": "2026-09-30"
  }'

Example Response

json
{
  "data": {
    "id": "clx1a2b3c4d5e6f7g8h9",
    "externalId": "EMP-1042",
    "firstName": "Jane",
    "lastName": "Chen-Rivera",
    "email": "jane.chen@example.com",
    "internalEmployeeId": "EMP-1042",
    "startDate": "2024-03-15",
    "endDate": "2026-12-31",
    "noticeDate": "2026-09-30",
    "managerId": "clx9m4n5o6p7q8r9",
    "jobRoleId": "clx9r8q7w6e5t4r3",
    "workTypeId": "clx2w3x4y5z6a7b8",
    "geographyId": "clx3g2h1j0k9l8m7",
    "defaultCurrencyCode": "USD",
    "createdAt": "2024-03-15T10:30:00Z",
    "updatedAt": "2026-04-08T09:20:00Z"
  }
}

Delete Employee

DELETE /org/:orgId/employees/:id

Deletes an employee record. This operation is permanent for live data. In scenario mode, it creates a soft-delete tombstone.

Example Request

bash
curl -X DELETE "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/employees/clx1a2b3c4d5e6f7g8h9" \
  -H "Authorization: Bearer private_..."

Status: 204 No Content


External IDs

You can assign your own externalId to employees during creation or update. This allows you to reference employees by your system's identifier instead of the Flowstate CUID.

  • Setting: Pass externalId in the POST or PATCH request body.
  • Lookups: Use the external ID directly in path parameters (e.g. GET /employees/EMP-1042).
  • Uniqueness: External IDs must be unique per entity type within your organization.
  • Format restriction: External IDs cannot match the CUID format (25 lowercase alphanumeric characters starting with a letter).
  • FK references: Fields like managerId also accept external IDs.

Error Responses

Validation Error (400)

Returned when the request body fails validation:

json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed.",
    "details": [
      { "field": "email", "message": "email must be a valid email address" },
      { "field": "startDate", "message": "startDate is required" }
    ],
    "errorId": "err_clx9a8b7c6d5e4f3"
  }
}

Not Found (404)

Returned when the employee ID does not exist:

json
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Employee not found.",
    "errorId": "err_clx9a8b7c6d5e4f3"
  }
}

  • Salary Adjustments -- Manage compensation history for an employee.
  • Assignments -- Manage team and project allocations.
  • Teams -- The teams employees can be assigned to.
  • Projects -- The projects employees can be allocated to.
  • Locations -- Geographic locations referenced by geographyId.
  • Work Types -- Work arrangement types referenced by workTypeId.
  • Custom Attributes -- Manage custom fields on employees.

Flowstate Documentation