Documentation Get help

Employees

An employee is a person on your payroll. Salary history lives in salary adjustments. Team and project time lives in assignments.

  • IDs. Paths take a Flowstate ID or your externalId. A value of 24–25 lowercase letters and digits that starts with a letter is read as a Flowstate ID. Anything else is read as an externalId.
  • Dates. Send YYYY-MM-DD, which is read as 00:00 UTC, or a full ISO 8601 date-time. Dates come back as ISO 8601 date-times, e.g. 2026-07-01T00:00:00.000Z.
  • Money. Amounts come back as decimal strings, e.g. "85000". Send them as numbers.
  • Scenarios. Live data only. See Scenarios.

The employee object

FieldTypeDescription
idstringFlowstate ID. Read-only.
externalIdstring | nullYour identifier. Unique among your employees, at most 255 characters, and can’t look like a Flowstate ID.
firstNamestringGiven name.
lastNamestringFamily name.
namestring | nullDisplay name, when set. Read-only.
emailstring | nullWork email. Unique among your employees.
internalEmployeeIdstring | nullYour HR system’s employee number.
startDatedatetimeFirst day of employment.
endDatedatetime | nullLast day of employment. null = no leave date.
noticeDatedatetime | nullDay notice was given.
managerIdstring | nullLine manager’s employee ID.
jobRoleIdstring | nullJob role ID.
workTypeIdstring | nullResource type ID.
geographyIdstring | nullLocation ID.
defaultCurrencyCodestring | nullISO 4217 code.
organizationId, correlationEmployeeId, sourceSystem, sourceSystemId, lastSyncedAt, metadataRecord-keeping. Read-only. sourceSystem is api for records created here.
createdAt, updatedAtdatetimeRead-only.
customAttributesarrayCustom attribute values. Returned by retrieve only.

Endpoints

MethodPathPermission
GET/api/v1/org/:orgId/employeesView Employees (team_employees_view)
GET/api/v1/org/:orgId/employees/:idView Employees (team_employees_view)
POST/api/v1/org/:orgId/employeesCreate Employees (team_employees_create)
PATCH/api/v1/org/:orgId/employees/:idUpdate Employees (team_employees_update)
DELETE/api/v1/org/:orgId/employees/:idDelete Employees (team_employees_delete)

Sub-resources: salary adjustments at /employees/:employeeId/salary-adjustments and custom attribute values at /employees/:id/custom-attributes.


List employees

GET /api/v1/org/:orgId/employees

Permission: View Employees (team_employees_view). With include=currentSalary or include=salaryHistory, you also need View Detailed Financials (financials_view_detailed).

Query parameters

ParameterTypeDefaultDescription
pageinteger1Page number, from 1.
limitinteger20Page size, 1–100.
searchstringCase-insensitive match on firstName, lastName or email.
sortBystringlastNamelastName, firstName, email or startDate. Any other value sorts by lastName.
sortDirstringascasc or desc.
includestringComma-separated. See Includes.

Includes

KeyAddsNeeds
currentSalaryThe salary adjustment with the latest effectiveDate, or null.financials_view_detailed
salaryHistoryEvery salary adjustment, latest effectiveDate first.financials_view_detailed
assignmentsEvery team and project assignment, past and current, latest startDate first. Each has type (team or project), targetId, employeeId, fte, startDate, endDate and role, along with the assignment’s own fields.

Example request

curl "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/employees?search=chen&limit=10" \
  -H "Authorization: Bearer private_..."

Example response

{
  "data": [
    {
      "id": "cmf2k8x1q0001ab2cd3ef4gh5",
      "organizationId": "cmf2k8x1q0000ab2cd3ef4gh5",
      "correlationEmployeeId": null,
      "firstName": "Jane",
      "lastName": "Chen",
      "name": "Jane Chen",
      "email": "jane.chen@example.com",
      "internalEmployeeId": "HR-1042",
      "externalId": "EMP-1042",
      "startDate": "2024-03-15T00:00:00.000Z",
      "endDate": null,
      "managerId": "cmf2k8x1q0002ab2cd3ef4gh5",
      "jobRoleId": "cmf2k8x1q0010ab2cd3ef4gh5",
      "workTypeId": "cmf2k8x1q0011ab2cd3ef4gh5",
      "geographyId": "cmf2k8x1q0012ab2cd3ef4gh5",
      "defaultCurrencyCode": "GBP",
      "sourceSystem": "api",
      "sourceSystemId": null,
      "lastSyncedAt": "2024-03-15T10:30:00.000Z",
      "metadata": {},
      "createdAt": "2024-03-15T10:30:00.000Z",
      "updatedAt": "2026-06-01T14:22:00.000Z",
      "noticeDate": null
    }
  ],
  "meta": { "page": 1, "limit": 10, "total": 1, "hasNextPage": false }
}

Errors

StatusCodeWhen
400VALIDATION_ERRORInvalid query parameter, or an include key not in the table.
403FORBIDDENA salary include without financials_view_detailed.

Retrieve an employee

GET /api/v1/org/:orgId/employees/:id

Permission: View Employees (team_employees_view). The salary includes also need financials_view_detailed.

Takes the same include parameter as List employees. The response is the employee object, with customAttributes and any includes.

Example request

curl "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/employees/EMP-1042?include=currentSalary" \
  -H "Authorization: Bearer private_..."

Example response

{
  "data": {
    "id": "cmf2k8x1q0001ab2cd3ef4gh5",
    "firstName": "Jane",
    "lastName": "Chen",
    "externalId": "EMP-1042",
    "startDate": "2024-03-15T00:00:00.000Z",
    "endDate": null,
    "defaultCurrencyCode": "GBP",
    "…": "other employee fields",
    "customAttributes": [],
    "currentSalary": {
      "id": "cmf2k8x1q0040ab2cd3ef4gh5",
      "organizationId": "cmf2k8x1q0000ab2cd3ef4gh5",
      "liveEmployeeId": "cmf2k8x1q0001ab2cd3ef4gh5",
      "effectiveDate": "2026-01-01T00:00:00.000Z",
      "salary": "95000",
      "bonus": "10000",
      "currencyCode": "GBP",
      "reason": "Annual review",
      "sourceSystem": "api",
      "sourceSystemId": null,
      "lastSyncedAt": "2025-12-15T10:30:00.000Z",
      "metadata": {},
      "createdAt": "2025-12-15T10:30:00.000Z",
      "updatedAt": "2025-12-15T10:30:00.000Z"
    }
  }
}

Errors

StatusCodeWhen
400VALIDATION_ERRORAn include key not in the table.
403FORBIDDENA salary include without financials_view_detailed.
404NOT_FOUNDNo employee with that ID or externalId.

Create an employee

POST /api/v1/org/:orgId/employees

Permission: Create Employees (team_employees_create).

The employee is created in one transaction with any nested salary, teamAssignment and projectAssignment you send.

Body parameters

FieldTypeRequiredDescription
firstNamestringYes
lastNamestringYes
emailstringYesValid email address, unique among your employees.
startDatedateYes
externalIdstring | nullNoAt most 255 characters. Can’t look like a Flowstate ID.
internalEmployeeIdstring | nullNo
endDatedate | nullNo
noticeDatedate | nullNo
managerIdstring | nullNoEmployee ID or externalId.
jobRoleIdstring | nullNoJob role ID. Wins over jobRole.
jobRoleobjectNoFind or create a job role. See jobRole.
workTypeIdstring | nullNoResource type ID.
geographyIdstring | nullNoLocation ID.
defaultCurrencyCodestring | nullNoThree uppercase letters.
salaryobjectNoFirst salary adjustment. See salary.
teamAssignmentobjectNoSee teamAssignment and projectAssignment.
projectAssignmentobjectNoSee teamAssignment and projectAssignment.

jobRole

Matched by externalId first, then by title. With no match, a role is created from title. Send at least one of the two.

FieldTypeDescription
titlestring1–255 characters. Needed to create a role.
externalIdstring1–255 characters. A role matched by title that has no externalId takes this one.

salary

FieldTypeRequiredDescription
effectiveDatedateYes
salarynumberYesAnnual base salary, ≥ 0.
currencyCodestringYesThree uppercase letters.
bonusnumber | nullNoAnnual bonus, ≥ 0.
reasonstring | nullNo

teamAssignment and projectAssignment

FieldTypeRequiredDescription
teamId / projectIdstringYesTeam or project ID, or its externalId.
ftenumberYes0–10. 1 = full time.
startDatedateYes
endDatedate | nullNonull = open-ended.
rolestring | nullNo

Example request

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-10-01",
    "managerId": "EMP-1042",
    "jobRole": { "title": "Senior Engineer", "externalId": "ROLE-042" },
    "geographyId": "cmf2k8x1q0012ab2cd3ef4gh5",
    "defaultCurrencyCode": "GBP",
    "salary": {
      "effectiveDate": "2026-10-01",
      "salary": 85000,
      "currencyCode": "GBP",
      "reason": "Starting salary"
    },
    "teamAssignment": {
      "teamId": "cmf2k8x1q0020ab2cd3ef4gh5",
      "fte": 1,
      "startDate": "2026-10-01"
    }
  }'

Example response

201 Created. When you sent them, the created records come back under salary, teamAssignment and projectAssignment.

{
  "data": {
    "id": "cmf2k8x1q0003ab2cd3ef4gh5",
    "organizationId": "cmf2k8x1q0000ab2cd3ef4gh5",
    "correlationEmployeeId": null,
    "firstName": "Alex",
    "lastName": "Rivera",
    "name": null,
    "email": "alex.rivera@example.com",
    "internalEmployeeId": null,
    "externalId": "EMP-2001",
    "startDate": "2026-10-01T00:00:00.000Z",
    "endDate": null,
    "managerId": "cmf2k8x1q0001ab2cd3ef4gh5",
    "jobRoleId": "cmf2k8x1q0010ab2cd3ef4gh5",
    "workTypeId": null,
    "geographyId": "cmf2k8x1q0012ab2cd3ef4gh5",
    "defaultCurrencyCode": "GBP",
    "sourceSystem": "api",
    "sourceSystemId": null,
    "lastSyncedAt": "2026-09-14T09:15:00.000Z",
    "metadata": {},
    "createdAt": "2026-09-14T09:15:00.000Z",
    "updatedAt": "2026-09-14T09:15:00.000Z",
    "noticeDate": null,
    "salary": {
      "id": "cmf2k8x1q0041ab2cd3ef4gh5",
      "liveEmployeeId": "cmf2k8x1q0003ab2cd3ef4gh5",
      "effectiveDate": "2026-10-01T00:00:00.000Z",
      "salary": "85000",
      "bonus": null,
      "currencyCode": "GBP",
      "reason": "Starting salary",
      "…": "other salary adjustment fields"
    },
    "teamAssignment": {
      "id": "cmf2k8x1q0050ab2cd3ef4gh5",
      "liveEmployeeId": "cmf2k8x1q0003ab2cd3ef4gh5",
      "liveTeamId": "cmf2k8x1q0020ab2cd3ef4gh5",
      "fte": 1,
      "startDate": "2026-10-01T00:00:00.000Z",
      "endDate": null,
      "role": null,
      "…": "other assignment fields"
    }
  }
}

Errors

StatusCodeWhen
400VALIDATION_ERRORThe body is invalid, teamAssignment.teamId or projectAssignment.projectId matches nothing, or email or externalId is already used.
404NOT_FOUNDmanagerId matches no employee, or jobRole has only an externalId that matches no role.
501NOT_IMPLEMENTEDscenarioId was sent.

Update an employee

PATCH /api/v1/org/:orgId/employees/:id

Permission: Update Employees (team_employees_update).

Takes the create body with every field optional. Send only what changes. null clears a nullable field. email can’t be cleared.

Nested salary, teamAssignment and projectAssignment always add a record. They never change or end an existing one. To change those, use salary adjustments and assignments.

Example request

curl -X PATCH "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/employees/EMP-1042" \
  -H "Authorization: Bearer private_..." \
  -H "Content-Type: application/json" \
  -d '{ "lastName": "Chen-Rivera" }'

Example response

200 OK. The response is the updated employee, plus any nested records created.

Errors

As for Create an employee, plus 404 NOT_FOUND when no employee has that ID or externalId.


Delete an employee

DELETE /api/v1/org/:orgId/employees/:id

Permission: Delete Employees (team_employees_delete).

Permanent. The following are deleted with the employee:

  • salary adjustments
  • assignments
  • leave
  • effort records

Where another record points to the employee as its manager, hiring manager or vacancy filler, that link is set to null. To record someone leaving, set endDate instead. See Record a leaver.

Example request

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

Example response

{ "data": { "id": "cmf2k8x1q0001ab2cd3ef4gh5", "deleted": true } }

Errors

StatusCodeWhen
404NOT_FOUNDNo employee with that ID or externalId.
501NOT_IMPLEMENTEDscenarioId was sent.

Tasks

Record a leaver

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

The employee’s assignments keep their own end dates. End any that should stop on the leaving date with PATCH /assignments/employees/:id. To withdraw a resignation, send "endDate": null, "noticeDate": null.

Sync from an HR system by your own ID

Create with externalId, then use it in paths (/employees/EMP-1042) and in managerId. Before creating, GET /employees/EMP-1042: a 404 means the employee doesn’t exist yet. The full walkthrough is in Recipes.