Documentation Get help

Vacancies

A vacancy is a planned hire: a role, dates, FTE and salary, with team and project assignments like a person’s. Fill a vacancy creates the employee or contractor who takes it.

  • 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. "90000". Send them as numbers.
  • Scenarios. Live data only. See Scenarios.

The vacancy object

FieldTypeDescription
idstringFlowstate ID. Read-only.
externalIdstring | nullYour identifier, e.g. a requisition number. Unique among your vacancies, at most 255 characters, and can’t look like a Flowstate ID.
rolestringTitle of the role.
namestring | nullDisplay name, when set. Read-only.
descriptionstring | null
statusstringopen, committed (approved, not yet filled), filled or cancelled.
ftenumber0–1.
targetStartDatedatetime | nullPlanned start.
targetEndDatedatetime | nullLast day of a fixed-term role. null = permanent.
jobRoleIdstring | nullJob role ID.
workTypeIdstring | nullResource type ID.
geographyIdstring | nullLocation ID.
salarydecimal string | nullAnnual salary.
currencyCodestring | nullISO 4217 code for salary.
hiringManagerIdstring | nullHiring manager’s employee ID.
filledByLiveEmployeeIdstring | nullEmployee who filled it. Read-only; set by Fill a vacancy.
filledByLiveContractorIdstring | nullContractor who filled it. Read-only; set by Fill a vacancy. At most one of the two filledBy fields is set.
organizationId, correlationVacancyId, 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/vacanciesView Vacancies (team_vacancies_view)
GET/api/v1/org/:orgId/vacancies/:idView Vacancies (team_vacancies_view)
POST/api/v1/org/:orgId/vacanciesCreate Vacancies (team_vacancies_create)
PATCH/api/v1/org/:orgId/vacancies/:idUpdate Vacancies (team_vacancies_update)
DELETE/api/v1/org/:orgId/vacancies/:idDelete Vacancies (team_vacancies_delete)
POST/api/v1/org/:orgId/vacancies/:id/fillCreate Employees (team_employees_create)

Sub-resource: custom attribute values at /vacancies/:id/custom-attributes.


List vacancies

GET /api/v1/org/:orgId/vacancies

Permission: View Vacancies (team_vacancies_view).

Returns every vacancy, filled and cancelled ones included.

Query parameters

ParameterTypeDefaultDescription
pageinteger1Page number, from 1.
limitinteger20Page size, 1–100.
searchstringCase-insensitive match on role or description.
sortBystringrolerole, status, targetStartDate or targetEndDate. Any other value sorts by role.
sortDirstringascasc or desc.

Example request

curl "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/vacancies?sortBy=targetStartDate" \
  -H "Authorization: Bearer private_..."

Example response

{
  "data": [
    {
      "id": "cmf2k8x1q0070ab2cd3ef4gh5",
      "organizationId": "cmf2k8x1q0000ab2cd3ef4gh5",
      "correlationVacancyId": null,
      "externalId": "REQ-2207",
      "role": "Senior Backend Engineer",
      "name": "Senior Backend Engineer",
      "description": "Payments platform.",
      "status": "open",
      "fte": 1,
      "targetStartDate": "2026-11-01T00:00:00.000Z",
      "targetEndDate": null,
      "jobRoleId": "cmf2k8x1q0010ab2cd3ef4gh5",
      "workTypeId": "cmf2k8x1q0011ab2cd3ef4gh5",
      "geographyId": "cmf2k8x1q0012ab2cd3ef4gh5",
      "salary": "90000",
      "currencyCode": "GBP",
      "filledByLiveEmployeeId": null,
      "filledByLiveContractorId": null,
      "hiringManagerId": "cmf2k8x1q0001ab2cd3ef4gh5",
      "sourceSystem": "api",
      "sourceSystemId": null,
      "lastSyncedAt": "2026-08-03T10:00:00.000Z",
      "metadata": {},
      "createdAt": "2026-08-03T10:00:00.000Z",
      "updatedAt": "2026-09-01T16:45:00.000Z"
    }
  ],
  "meta": { "page": 1, "limit": 20, "total": 1, "hasNextPage": false }
}

Errors

StatusCodeWhen
400VALIDATION_ERRORInvalid query parameter.

Retrieve a vacancy

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

Permission: View Vacancies (team_vacancies_view).

The response is the vacancy object, with customAttributes and any includes.

Includes

Pass include as a comma-separated list.

KeyAdds
assignmentsEvery team and project assignment. Each is { id, type, targetId, fte, startDate, endDate, createdAt, updatedAt }, where type is team or project.
filledByEmployeeThe employee in filledByLiveEmployeeId. Left out when that field is null.

Example request

curl "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/vacancies/REQ-2207?include=assignments" \
  -H "Authorization: Bearer private_..."

Example response

{
  "data": {
    "id": "cmf2k8x1q0070ab2cd3ef4gh5",
    "externalId": "REQ-2207",
    "role": "Senior Backend Engineer",
    "status": "open",
    "…": "other vacancy fields",
    "customAttributes": [],
    "assignments": [
      {
        "id": "cmf2k8x1q0054ab2cd3ef4gh5",
        "type": "team",
        "targetId": "cmf2k8x1q0020ab2cd3ef4gh5",
        "fte": 1,
        "startDate": "2026-11-01T00:00:00.000Z",
        "endDate": null,
        "createdAt": "2026-08-03T10:00:00.000Z",
        "updatedAt": "2026-08-03T10:00:00.000Z"
      }
    ]
  }
}

Errors

StatusCodeWhen
400VALIDATION_ERRORAn include key not in the table.
404NOT_FOUNDNo vacancy with that ID or externalId.

Create a vacancy

POST /api/v1/org/:orgId/vacancies

Permission: Create Vacancies (team_vacancies_create).

Body parameters

FieldTypeRequiredDescription
rolestringYes
externalIdstring | nullNoAt most 255 characters. Can’t look like a Flowstate ID.
descriptionstring | nullNo
statusstringNoDefault open.
ftenumberNo0–1. Default 1.
targetStartDatedate | nullNo
targetEndDatedate | nullNoOn or after targetStartDate.
jobRoleIdstring | nullNoJob role ID. Wins over jobRole.
jobRoleobjectNoFind or create a job role by externalId or title. Same shape as on employees.
workTypeIdstring | nullNoResource type ID.
geographyIdstring | nullNoLocation ID.
salarynumber | nullNoAnnual salary, ≥ 0.
currencyCodestring | nullNoThree uppercase letters.
hiringManagerIdstring | nullNoEmployee ID or externalId.
salaryMin, salaryMaxnumber | nullNoDeprecated. Use salary. When salary is absent, both bounds are stored as their midpoint, and one bound alone is stored as it is.

A new vacancy has no assignments. Add them with POST /assignments/vacancies.

Example request

curl -X POST "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/vacancies" \
  -H "Authorization: Bearer private_..." \
  -H "Content-Type: application/json" \
  -d '{
    "role": "Senior Backend Engineer",
    "externalId": "REQ-2207",
    "description": "Payments platform.",
    "targetStartDate": "2026-11-01",
    "salary": 90000,
    "currencyCode": "GBP",
    "hiringManagerId": "EMP-1042"
  }'

Example response

201 Created. The response is the vacancy object.

Errors

StatusCodeWhen
400VALIDATION_ERRORThe body is invalid, targetEndDate is before targetStartDate, or externalId is already used.
404NOT_FOUNDhiringManagerId matches no employee, or jobRole has only an externalId that matches no role.
501NOT_IMPLEMENTEDscenarioId was sent.

Update a vacancy

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

Permission: Update Vacancies (team_vacancies_update).

Takes the create body with every field optional. null clears a nullable field. An explicit salary wins over the deprecated range. The response is the updated vacancy, 200 OK.

Dates are checked against the stored record, so targetEndDate alone can’t go before the existing targetStartDate. After each update, the vacancy’s team and project assignments are moved to fit its targetStartDate and targetEndDate.

Example request

curl -X PATCH "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/vacancies/REQ-2207" \
  -H "Authorization: Bearer private_..." \
  -H "Content-Type: application/json" \
  -d '{ "status": "committed", "targetStartDate": "2027-01-04" }'

Errors

As for Create a vacancy, plus 404 NOT_FOUND when no vacancy has that ID or externalId.


Delete a vacancy

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

Permission: Delete Vacancies (team_vacancies_delete).

Permanent. The vacancy’s team and project assignments are deleted with it. To withdraw a role and keep its record, set status to cancelled.

Example response

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

Errors

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

Fill a vacancy

POST /api/v1/org/:orgId/vacancies/:id/fill

Permission: Create Employees (team_employees_create), for both branches.

One transaction does four things:

  1. Creates the filler. This is an employee with a salary adjustment, or a contractor with a rate adjustment. The adjustment is effective from startDate.
  2. Ends the vacancy’s assignments. Each assignment with no end date ends the day before startDate.
  3. Starts new assignments. A copy of each one starts on startDate for the filler, on the same team or project at the same FTE.
  4. Marks the vacancy filled. It sets status to filled and sets filledByLiveEmployeeId or filledByLiveContractorId.

If you leave out managerId, workTypeId or geographyId, the vacancy’s hiringManagerId, workTypeId or geographyId is used. Employees also take the vacancy’s jobRoleId when you leave it out.

Body parameters

FieldTypeRequiredDescription
fillerTypestringNoemployee (default) or contractor.
startDatedateYesFiller’s first day.
currencyCodestringYesThree uppercase letters, for salary or rate.
emailstring | nullNoWork email. For an employee, send it: without it Flowstate sets a placeholder address.
managerIdstring | nullNoEmployee ID or externalId.
workTypeIdstring | nullNoResource type ID.
geographyIdstring | nullNoLocation ID.
firstNamestringEmployee
lastNamestringEmployee
salarynumberEmployeeAnnual base salary, ≥ 0.
jobRoleIdstring | nullNoEmployee only. Wins over jobRole.
jobRoleobjectNoEmployee only. Same shape as on employees.
namestringContractor
ratenumberContractor≥ 0.
rateTypestringContractorhourly, daily, monthly or annually.
contractorTypestringNoContractor only. Default individual.

Sending the other branch’s fields is a 400. For example, name with fillerType: "employee" is rejected.

Example request: employee

curl -X POST "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/vacancies/REQ-2207/fill" \
  -H "Authorization: Bearer private_..." \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Sarah",
    "lastName": "Okonkwo",
    "email": "sarah.okonkwo@example.com",
    "startDate": "2026-11-01",
    "salary": 90000,
    "currencyCode": "GBP"
  }'

Example request: contractor

curl -X POST "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/vacancies/REQ-2207/fill" \
  -H "Authorization: Bearer private_..." \
  -H "Content-Type: application/json" \
  -d '{
    "fillerType": "contractor",
    "name": "Marco Bianchi",
    "startDate": "2026-11-01",
    "rate": 700,
    "rateType": "daily",
    "currencyCode": "GBP"
  }'

Example response

200 OK. One of employee and contractor is set; the other is null.

{
  "data": {
    "employee": {
      "id": "cmf2k8x1q0004ab2cd3ef4gh5",
      "firstName": "Sarah",
      "lastName": "Okonkwo",
      "email": "sarah.okonkwo@example.com",
      "startDate": "2026-11-01T00:00:00.000Z",
      "managerId": "cmf2k8x1q0001ab2cd3ef4gh5",
      "jobRoleId": "cmf2k8x1q0010ab2cd3ef4gh5",
      "workTypeId": "cmf2k8x1q0011ab2cd3ef4gh5",
      "geographyId": "cmf2k8x1q0012ab2cd3ef4gh5",
      "defaultCurrencyCode": "GBP",
      "…": "other employee fields"
    },
    "contractor": null,
    "vacancyId": "cmf2k8x1q0070ab2cd3ef4gh5",
    "teamAllocationsTransferred": 1,
    "projectAllocationsTransferred": 0
  }
}

Errors

StatusCodeWhen
400VALIDATION_ERRORA required field for the branch is missing, the other branch’s fields were sent, or email is already used.
404NOT_FOUNDNo vacancy with that ID or externalId, managerId matches no employee, or jobRole has only an externalId that matches no role.
409CONFLICTThe vacancy’s status is filled, or a filler is already linked.
501NOT_IMPLEMENTEDscenarioId was sent.

Tasks

Move a start date

PATCH the vacancy’s targetStartDate. Its assignments move with it. There’s no need to update them separately.

Make a role fixed-term

PATCH with targetEndDate. Assignments that ran past it now end on it. Send "targetEndDate": null to make the role permanent again.