Appearance
Vacancies
Manage open positions and the hiring pipeline. Vacancies represent roles that need to be filled, with target dates, salary ranges, and team assignments. When a candidate is hired, you can "fill" a vacancy to atomically convert it into an employee record.
New to Flowstate?
Read the Domain Model to understand the vacancy-to-employee fill workflow and how vacancies feed into headcount forecasting.
Vacancy Object
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier (CUID format). System-generated. Read-only. |
externalId | string | null | Your external identifier for this vacancy. Unique within your organization. Use for lookups via path parameters. |
role | string | Vacancy title / role name (e.g. "Senior Backend Engineer"). |
description | string | null | Detailed description of the role and responsibilities. |
status | string | Vacancy status: "open", "filled", "cancelled", or "on_hold". |
fte | number | Full-Time Equivalent for this vacancy. 1.0 = full-time, 0.5 = half-time. Range: 0--1. |
targetStartDate | date (YYYY-MM-DD) | null | Desired start date for the new hire. Used in headcount forecasting. |
targetFillDate | date (YYYY-MM-DD) | null | Target date to fill this vacancy by. Used for recruitment planning. |
jobRoleId | string | null | Job role classification. Use GET /job-roles for valid IDs. |
workTypeId | string | null | Work arrangement type. References a Work Type. |
geographyId | string | null | Target hire location/region. References a Location. Affects salary range expectations. |
salaryMin | number | null | Minimum annual salary for the role. Decimal with 2 decimal places. |
salaryMax | number | null | Maximum annual salary for the role. Decimal with 2 decimal places. |
currencyCode | string | null | ISO 4217 currency code for the salary range (e.g. "GBP"). |
filledByLiveEmployeeId | string | null | ID of the employee who filled this vacancy. Set automatically by the Fill endpoint, or manually via PATCH. References an Employee. |
hiringManagerId | string | null | ID of the employee responsible for hiring this role. References an Employee. |
createdAt | datetime (ISO 8601) | When the record was created. Read-only. |
updatedAt | datetime (ISO 8601) | When the record was last modified. Read-only. |
customAttributes | array | Custom attribute values for this vacancy. Returned on GET-by-ID. See Custom Attributes. |
Endpoints
| Method | Path | Description |
|---|---|---|
GET | /org/:orgId/vacancies | List vacancies |
GET | /org/:orgId/vacancies/:id | Get vacancy |
POST | /org/:orgId/vacancies | Create vacancy |
PATCH | /org/:orgId/vacancies/:id | Update vacancy |
DELETE | /org/:orgId/vacancies/:id | Delete vacancy |
POST | /org/:orgId/vacancies/:id/fill | Fill a vacancy (convert to employee) |
External ID Support
The :id path parameter accepts either a Flowstate CUID (e.g. clx1a2b3c4d5e6f7g8h9) or your externalId. The format is auto-detected.
List Vacancies
GET /org/:orgId/vacanciesReturns a paginated list of vacancies in the organization.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number (1-based). |
limit | integer | 20 | Records per page. Min 1, max 100. |
search | string | -- | Free-text search by role or description. |
sortBy | string | role | Field to sort by. |
sortDir | string | asc | Sort direction: asc or desc. |
scenarioId | string | -- | Scenario ID for what-if queries. |
Example Request
bash
curl -X GET "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/vacancies?sortBy=targetStartDate&sortDir=asc" \
-H "Authorization: Bearer private_..."Example Response
json
{
"data": [
{
"id": "clx5v6w7x8y9z0a1b2c3",
"externalId": null,
"role": "Senior Backend Engineer",
"description": "Backend engineer for the payments team, focusing on billing infrastructure.",
"status": "open",
"fte": 1.0,
"targetStartDate": "2026-06-01",
"targetFillDate": "2026-05-15",
"jobRoleId": "clx9r8q7w6e5t4r3",
"workTypeId": "clx2w3x4y5z6a7b8",
"geographyId": "clx3g2h1j0k9l8m7",
"salaryMin": 120000,
"salaryMax": 160000,
"currencyCode": "USD",
"filledByLiveEmployeeId": null,
"hiringManagerId": "clx9m4n5o6p7q8r9",
"createdAt": "2026-01-15T10:00:00Z",
"updatedAt": "2026-03-01T16:45:00Z"
}
],
"meta": {
"page": 1,
"limit": 20,
"total": 23,
"hasNextPage": true
}
}Get Vacancy
GET /org/:orgId/vacancies/:idReturns a single vacancy by ID.
Including Related Data
| Include Key | Description |
|---|---|
assignments | All team and project assignments for this vacancy. |
filledByEmployee | The employee record that filled this vacancy (if status is "filled"). |
GET /org/:orgId/vacancies/:id?include=assignments,filledByEmployeeExample Request
bash
curl -X GET "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/vacancies/clx5v6w7x8y9z0a1b2c3?include=assignments" \
-H "Authorization: Bearer private_..."Example Response
json
{
"data": {
"id": "clx5v6w7x8y9z0a1b2c3",
"role": "Senior Backend Engineer",
"description": "Backend engineer for the payments team, focusing on billing infrastructure.",
"status": "open",
"fte": 1.0,
"targetStartDate": "2026-06-01",
"targetFillDate": "2026-05-15",
"jobRoleId": "clx9r8q7w6e5t4r3",
"workTypeId": "clx2w3x4y5z6a7b8",
"geographyId": "clx3g2h1j0k9l8m7",
"salaryMin": 120000,
"salaryMax": 160000,
"currencyCode": "USD",
"filledByLiveEmployeeId": null,
"hiringManagerId": "clx9m4n5o6p7q8r9",
"createdAt": "2026-01-15T10:00:00Z",
"updatedAt": "2026-03-01T16:45:00Z",
"customAttributes": [
{
"id": "clx0a1b2c3d4e5f6g7h8",
"definitionId": "clx2d3e4f5g6h7i8j9k0",
"entityType": "VACANCY",
"entityId": "clx5v6w7x8y9z0a1b2c3",
"stringValue": "ENG-001",
"numberValue": null,
"dateValue": null,
"dateRangeStart": null,
"dateRangeEnd": null,
"definition": {
"id": "clx2d3e4f5g6h7i8j9k0",
"name": "Cost Centre Code",
"attributeKey": "cost_centre_code",
"fieldType": "STRING"
}
}
],
"assignments": [
{
"id": "clx8a9b0c1d2e3f4",
"type": "team",
"targetId": "clx6t7u8v9w0x1y2",
"fte": 1.0,
"startDate": "2026-06-01",
"endDate": null,
"createdAt": "2026-01-15T10:00:00Z",
"updatedAt": "2026-01-15T10:00:00Z"
}
]
}
}Create Vacancy
POST /org/:orgId/vacanciesCreates a new vacancy record.
Create Request Body
| Field | Type | Required | Description |
|---|---|---|---|
role | string | Yes | Vacancy title or role name. |
externalId | string | null | No | Your external identifier. Must be unique within the organization. Cannot resemble a CUID format. Max 255 characters. |
description | string | null | No | Detailed role description. |
status | string | No | Vacancy status. Default: "open". |
fte | number | No | FTE value (0--1). Default: 1.0. |
targetStartDate | date (YYYY-MM-DD) | null | No | Desired start date for the new hire. |
targetFillDate | date (YYYY-MM-DD) | null | No | Target date to fill the vacancy. |
jobRoleId | string | null | No | Job role ID. Takes precedence over jobRole. |
jobRole | object | No | Resolve-or-create a job role by externalId or title. Ignored when jobRoleId is supplied. See Employees → Nested jobRole Object for the shape and semantics — identical here. |
workTypeId | string | null | No | Work Type ID. |
geographyId | string | null | No | Location ID. |
salaryMin | number | null | No | Minimum annual salary. Must be >= 0. |
salaryMax | number | null | No | Maximum annual salary. Must be >= 0. |
currencyCode | string | null | No | ISO 4217 currency code (3 uppercase letters). |
hiringManagerId | string | null | No | ID of the hiring manager (an employee). |
Example Request
bash
curl -X POST "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/vacancies" \
-H "Authorization: Bearer private_..." \
-H "Content-Type: application/json" \
-d '{
"role": "DevOps Engineer",
"description": "Cloud infrastructure engineer to support the platform team.",
"fte": 1.0,
"targetStartDate": "2026-09-01",
"targetFillDate": "2026-08-15",
"salaryMin": 110000,
"salaryMax": 145000,
"currencyCode": "USD",
"hiringManagerId": "clx9m4n5o6p7q8r9"
}'Example Response
json
{
"data": {
"id": "clx2b3c4d5e6f7g8h9i0",
"externalId": null,
"role": "DevOps Engineer",
"description": "Cloud infrastructure engineer to support the platform team.",
"status": "open",
"fte": 1.0,
"targetStartDate": "2026-09-01",
"targetFillDate": "2026-08-15",
"jobRoleId": null,
"workTypeId": null,
"geographyId": null,
"salaryMin": 110000,
"salaryMax": 145000,
"currencyCode": "USD",
"filledByLiveEmployeeId": null,
"hiringManagerId": "clx9m4n5o6p7q8r9",
"createdAt": "2026-04-08T09:30:00Z",
"updatedAt": "2026-04-08T09:30:00Z"
}
}Status: 201 Created
Update Vacancy
PATCH /org/:orgId/vacancies/:idUpdates one or more fields on an existing vacancy. Only include the fields you want to change. You can set or update the externalId field.
Update Request Body
All fields from the Create Request Body are accepted, and all are optional.
Example Request
bash
curl -X PATCH "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/vacancies/clx5v6w7x8y9z0a1b2c3" \
-H "Authorization: Bearer private_..." \
-H "Content-Type: application/json" \
-d '{
"status": "on_hold",
"targetFillDate": "2026-07-01"
}'Delete Vacancy
DELETE /org/:orgId/vacancies/:idDeletes a vacancy record.
Example Request
bash
curl -X DELETE "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/vacancies/clx5v6w7x8y9z0a1b2c3" \
-H "Authorization: Bearer private_..."Status: 204 No Content
Fill a Vacancy
POST /org/:orgId/vacancies/:id/fillConverts a vacancy into a new employee. This is an atomic operation that:
- Creates a new employee with the provided details.
- Creates an initial salary adjustment for the new employee.
- Transfers all team/project assignments from the vacancy to the new employee.
- Sets the vacancy status to
"filled"and links it to the new employee.
Fields not provided in the fill request fall back to the vacancy's values (e.g. jobRoleId, geographyId, workTypeId).
Fill Request Body
| Field | Type | Required | Description |
|---|---|---|---|
firstName | string | Yes | New employee's first name. |
lastName | string | Yes | New employee's last name. |
email | string | null | No | Work email. If omitted, a placeholder is generated. |
startDate | date (YYYY-MM-DD) | Yes | Employee start date. Vacancy assignments transfer from this date. |
salary | number | Yes | Annual base salary. Must be >= 0. |
currencyCode | string | Yes | ISO 4217 currency code for the salary (e.g. "GBP"). |
managerId | string | null | No | Employee ID of the new hire's manager. Falls back to the vacancy's hiringManagerId. |
jobRoleId | string | null | No | Job role ID. Falls back to the vacancy's jobRoleId. Takes precedence over jobRole. |
jobRole | object | No | Resolve-or-create a job role by externalId or title (same shape as on employees). Ignored when jobRoleId is supplied. |
workTypeId | string | null | No | Work type ID. Falls back to the vacancy's workTypeId. |
geographyId | string | null | No | Geography ID. Falls back to the vacancy's geographyId. |
Example Request
bash
curl -X POST "https://{tenant}.flowstate.inc/api/v1/org/{orgId}/vacancies/clx5v6w7x8y9z0a1b2c3/fill" \
-H "Authorization: Bearer private_..." \
-H "Content-Type: application/json" \
-d '{
"firstName": "Sarah",
"lastName": "Okonkwo",
"email": "sarah.okonkwo@example.com",
"startDate": "2026-06-01",
"salary": 140000,
"currencyCode": "USD"
}'Example Response
The response contains the newly created employee:
json
{
"data": {
"id": "clx7n8m9k0j1h2g3f4e5",
"firstName": "Sarah",
"lastName": "Okonkwo",
"email": "sarah.okonkwo@example.com",
"internalEmployeeId": null,
"startDate": "2026-06-01",
"endDate": null,
"noticeDate": null,
"managerId": "clx9m4n5o6p7q8r9",
"jobRoleId": "clx9r8q7w6e5t4r3",
"workTypeId": "clx2w3x4y5z6a7b8",
"geographyId": "clx3g2h1j0k9l8m7",
"defaultCurrencyCode": null,
"createdAt": "2026-04-08T10:00:00Z",
"updatedAt": "2026-04-08T10:00:00Z"
}
}Status: 201 Created
What happens behind the scenes
After a successful fill:
- The vacancy's
statusbecomes"filled"andfilledByLiveEmployeeIdpoints to the new employee. - A salary adjustment is created with the provided
salary,currencyCode, and the employee'sstartDateas theeffectiveDate. - All vacancy team/project assignments are duplicated as employee assignments, starting from the employee's
startDate. - The
managerIddefaults to the vacancy'shiringManagerIdif not provided. - The
jobRoleId,workTypeId, andgeographyIddefault to the vacancy's values if not provided.
External IDs
You can assign your own externalId during creation or update. This allows you to reference vacancies by your system's identifier instead of the Flowstate CUID.
- Setting: Pass
externalIdin the POST or PATCH request body. - Lookups: Use the external ID directly in path parameters (e.g.
GET /vacancies/MY-EXT-ID). - 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).
Error Responses
Validation Error (400)
json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed.",
"details": [
{ "field": "role", "message": "role is required" }
],
"errorId": "err_clx9a8b7c6d5e4f3"
}
}Not Found (404)
json
{
"error": {
"code": "NOT_FOUND",
"message": "Vacancy not found.",
"errorId": "err_clx9a8b7c6d5e4f3"
}
}Related Endpoints
- Employees -- Employee records created when vacancies are filled.
- Assignments -- Manage team and project allocations for vacancies.
- Teams -- Teams that vacancies can be assigned to.
- Projects -- Projects that vacancies can be allocated to.
- Recipes: Fill a Vacancy -- Step-by-step guide for the fill workflow.
- Custom Attributes -- Manage custom fields on vacancies.