Users
Some basic information about each user is stored on the user object directly, instead of in their master CV. Most importantly, the user holds the information to identify them in authentication and integrations (id, email, external_unique_id, upn).
You can build your own user integration on top of this API if you need something more flexible than periodically sending us updated user lists in CSV. See User Sync for the SCIM and CSV options.
Four of the endpoints below (POST /users, GET /users/find, and GET and PUT on /users/<user_id>) also appear in the Integrations API reference, where you can see every field and response code and try a request. This page is the complete narrative and also covers the endpoints the reference does not yet include: user search, the profile changes feed, and deleting a user.
Before you start
- Every request needs an
Authorizationheader, and requests with a body needContent-Type: application/json. See Authentication & Security. - Creating a user needs a key with
countrymanageraccess for its own country, orinternationalmanageraccess for any country. A key with onlyconsultantaccess cannot create users. <user_id>in the URLs below is the internal Flowcase ID for the user.- Language codes are legacy by default (
intfor English,nofor Norwegian). Pass?use_legacy_codes=falseto read and write ISO 639-1 codes instead. See Country & Language Codes and multilingual text fields.
Search users
GET https://<subdomain>.flowcase.com/api/v2/users/search?from=<from>&size=<size>&sort_by=<sort_by>&deactivated=<deactivated>&role=<role>&name=<name>&office_ids[]=<office_id>&office_ids[]=<office_id>
Query parameters
| Parameter | Type | Description |
|---|---|---|
from |
integer | Used for pagination. Specifies the starting index of the results to return. Increase it by size to retrieve the next page. The response is a plain array with no total count, so keep requesting pages until you receive fewer than size results. |
size |
integer [1-500] | Used for pagination. Specifies the maximum number of results to return per page. Supports up to 500 items per page. |
sort_by |
string | Specifies the field to sort the results by. Supported values are: - name: Sort by name alphabetically ascending (default if not provided)- relevance: Sort by how well the name matches the provided name parameter, with more similar matches returned first- country: Sort by the ISO country code- role: Deprecated parameter, with no guaranteed consistency in sorting order |
deactivated |
boolean | Specifies whether to include deactivated users in the results. Set to true to include deactivated users, false to exclude them. |
role |
string | Limits the results to users with the specified role, such as consultant, external, referencemanager, countrymanager, departmentmanager, internationalmanager, or limited_access. |
name |
string | Limits the results to users whose name, email address, or external_unique_id matches or is similar to the provided name. |
office_ids |
array[string] | Limits the results to users from the specified office IDs. You can provide this parameter multiple times to include multiple office IDs. |
Response body
[
{
"user_id": "USER_ID",
"id": "USER_ID",
"email": "EMAIL",
"external_unique_id": "EXTERNAL_UNIQUE_ID",
"upn": "UPN",
"name": "NAME",
"telephone": "",
"default_cv_id": "CV_ID",
"deactivated": false,
"deactivated_at": false,
"created_at": "2016-12-01T13:54:07.000Z",
"updated_at": "2022-06-14T12:26:13.682Z",
"profile_updated_at": "2022-06-14T12:26:13.000Z",
"role": "internationalmanager",
"roles": ["internationalmanager"],
"office_id": "OFFICE_ID",
"office_name": "London",
"country_id": "COUNTRY_ID",
"country_code": "uk",
"language_code": "int",
"image": {
"url": null,
"thumb": { "url": null },
"fit_thumb": { "url": null },
"large": { "url": null },
"small_thumb": { "url": null }
}
// Some fields have been omitted
}
// More matching users
]
Get a user by ID
GET https://<subdomain>.flowcase.com/api/v1/users/<user_id>
<user_id> is the internal Flowcase ID for the user.
The user must belong to the same account as the API key. An ID from another account returns 404, as does an ID that does not exist or is not a valid ID, so you cannot tell the three apart.
Response body
{
"user_id": "USER_ID",
"id": "USER_ID",
"email": "EMAIL",
"external_unique_id": "EXTERNAL_UNIQUE_ID",
"upn": "UPN",
"name": "NAME",
"telephone": "",
"default_cv_id": "CV_ID",
"deactivated": false,
"deactivated_at": false,
"created_at": "2016-12-01T13:54:07.000Z",
"updated_at": "2022-06-14T12:26:13.682Z",
"role": "internationalmanager",
"roles": ["internationalmanager"],
"role_allowed_office_ids": [],
"role_allowed_tag_ids": [],
"office_id": "OFFICE_ID",
"office_name": "London",
"country_id": "COUNTRY_ID",
"country_code": "uk",
"language_code": "int",
"image": {
"url": null,
"thumb": { "url": null },
"fit_thumb": { "url": null },
"large": { "url": null },
"small_thumb": { "url": null }
}
// Some fields have been omitted
}
Three details are worth knowing when you read a user:
rolesholds the base role plus any extra access roles. Requests set the two separately, asroleandextra_roles, but the response reports them together inroles. See User roles.deactivated_atis booleanfalsewhile the user is active, and an ISO 8601 timestamp once the user has been deactivated.imageURLs are signed and expire after about 20 minutes, so fetch the picture rather than storing the URL. See Profile Pictures for uploads.
For the full field list, see the Integrations API reference.
Find a user by email, external ID or UPN
GET https://<subdomain>.flowcase.com/api/v1/users/find?<field>=<value>
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
email |
string | optional | Filter users based on email address match |
external_unique_id |
string | optional | Filter users based on external_unique_id match |
upn |
string | optional | Filter users based on upn match |
Each field is matched exactly. At least one of the three is needed: a request with none of them, or with only empty values, returns 400. Give two or more and the user has to match all of them. A query that matches nothing returns 404.
The response body is the same as getting a user by ID.
Track profile changes
GET https://<subdomain>.flowcase.com/api/v1/users/changes?profile_updated_since=<timestamp>&after_id=<user_id>&limit=<limit>
Returns the users whose profile data changed at or after profile_updated_since, oldest change first. Poll this endpoint to keep a copy of our user data up to date without reading every user on every run.
Every user carries a profile_updated_at timestamp, and this endpoint filters and orders by it. It moves only when profile data changes, so sign-in activity, password changes, UI preferences and role changes do not bring a user back. The fields that do move it are listed under Profile fields.
This endpoint needs an API key with the internationalmanager or readonly_internationalmanager role, shown as Administrator and Read only Administrator when you create a key, and answers 403 for any other role. It returns every user in the account, deactivated users included, because a profile that changed on the way out is still a change you need.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
profile_updated_since |
string | required | ISO 8601 timestamp. Users stamped at exactly this time are included, which is what makes the cursor below work. |
after_id |
string | optional | The id of the last user on the previous page. That user is left out of the results. |
limit |
integer | optional | Maximum number of users per page, must be positive. Default: 100 |
offset is not supported and returns 400. Page with after_id instead. A created_since parameter is accepted and ignored.
Response body
An array of user objects, each the same shape as getting a user by ID plus the profile_updated_at timestamp the feed orders by, ordered by profile_updated_at and then by id.
[
{
"user_id": "USER_ID",
"id": "USER_ID",
"email": "EMAIL",
"name": "NAME",
"updated_at": "2026-09-01T08:41:02.117Z",
"profile_updated_at": "2026-09-01T09:12:44.000Z"
// Same fields as a single user
}
// More changed users, later changes last
]
Reading the whole feed
Take the last user on the page you received, and send its profile_updated_at back as profile_updated_since and its id as after_id:
GET https://<subdomain>.flowcase.com/api/v1/users/changes?profile_updated_since=2026-09-01T09:12:44.000Z&after_id=USER_ID&limit=100
Repeat until a page comes back with fewer users than limit, which means you have reached the end. Keep that last cursor and send it again on your next poll.
Two details to respect when you build the cursor:
- Send the two values back as you received them. Every
profile_updated_atis a whole second, and a cursor built from a rounded or reformatted value can step over users. after_idis what separates users who share a timestamp. A bulk import can stamp thousands of users in the same second, so a cursor carrying only the timestamp will either repeat that group for ever or lose the rest of it.
Profile fields
A change to any of these moves profile_updated_at:
name, name_multilang, title, born_year, email, external_unique_id, upn, telephone, landline, place_of_residence, nationality, twitter, override_language_code, office_id, and the profile picture (image and its dimensions).
Custom tag assignments move it too. Tags are not part of the user object, so a user can appear in the feed with nothing visibly different: read their tags with the Custom Tags API if you track them.
Deactivating or reactivating a user does not move it, and neither does a role change, so neither event brings a user into the feed on its own. If you need to catch leavers or permission changes, read the full list with Search users on a slower schedule.
Create a user
POST https://<subdomain>.flowcase.com/api/v1/users
email, country_id and office_id are required, and the office must belong to that country. The email must be unique in the account, and its domain must be on the account's whitelist unless the user is given the external role.
Request body
{
"user": {
"country_id": "<country_id>",
"email": "<email_address>",
"upn": "<upn>",
"external_unique_id": "<employee_id>",
"office_id": "<office_id>",
"role": "<role>",
"extra_roles": [],
"name": "<name>",
"telephone": "<telephone>",
"landline": "<landline>",
"born_year": <born_year>,
"title": {
"no": "<title.no>",
"int": "<title.int>"
},
"nationality": {
"no": "<nationality.no>",
"int": "<nationality.int>"
},
"ensure_unique_custom_tag_ids_by_category": {
"<custom_tag_category_id>": "<custom_tag_id>"
},
"send_email": <send_email>
}
}
If send_email is set to true then an email notification is sent to the user. The send_email property should be omitted or false to create the user without sending an email.
ensure_unique_custom_tag_ids_by_category will add the provided custom tags to the user and remove any other custom tag the user has within that category. You have to use the internal ids for this (not the external_unique_id values). To get a list of all the existing tags and categories:
GET https://<subdomain>.flowcase.com/api/v1/masterdata/custom_tags/custom_tag_category
(See the Custom Tags documentation for more details.)
Response
A successful create answers 200, not 201, and returns the full user object.
| Status | Meaning |
|---|---|
400 |
The user wrapper key is missing from the request body. |
403 |
The key may not create users in that country, or the key is disabled. |
404 |
The country_id or office_id does not exist in the account. |
415 |
The Content-Type header is not application/json. |
422 |
Validation failed: a duplicate email or external_unique_id, or an email or UPN domain that is not whitelisted. |
See Response Codes for the full list.
Update a user
When updating a user it is only necessary to provide the fields that are to be updated, any fields omitted from the payload will remain as they were in the database.
PUT https://<subdomain>.flowcase.com/api/v1/users/<user_id>
Changing a user's office or department
In the case of changing the office_id (department), you also need to provide the country_id for the country that the new office is in. Changing the country needs internationalmanager access; moving a user between offices in the same country needs internationalmanager or countrymanager access.
Request body
{
"user": {
"country_id": "<country_id>",
"office_id": "<office_id>", // country_id is also required when changing the office_id
"email": "<email_address>",
"external_unique_id": "<employee_id>",
"name": "<name>",
"telephone": "<telephone>",
"landline": "<landline>",
"born_year": <born_year>,
"ensure_unique_custom_tag_ids_by_category": {
"<custom_tag_category_id>": "<custom_tag_id>"
},
"role": "consultant", // See User roles section
"extra_roles": []
}
}
ensure_unique_custom_tag_ids_by_category will add the provided custom tags to the user and remove any other custom tag the user has within that category.
Use the internal id values for both the category and the tag. A category or tag ID that does not exist in the account returns 400. To assign more than one tag from the same category, or to work with tags on their own, use the Custom Tags API.
Response
A successful update answers 200 and returns the full updated user object. It answers 400 when the user wrapper key is missing, 403 without write access to that user, 404 when no such user exists in the account, 415 when Content-Type is not application/json, and 422 when validation fails, for example a blank email, an email already used by another user, or an email or UPN domain that is not whitelisted.
Deactivate a user
PUT https://<subdomain>.flowcase.com/api/v1/users/<user_id>
<user_id> is the internal Flowcase ID for the user.
Request body
{
"user": {
"deactivated": true
}
}
Reactivate a user
PUT https://<subdomain>.flowcase.com/api/v1/users/<user_id>
<user_id> is the internal Flowcase ID for an existing user that was previously deactivated.
Request body
{
"user": {
"deactivated": false,
"send_email": false
}
}
If send_email is set to true then a welcome email will be sent to the activated user. The send_email property should be omitted or false to reactivate the user without sending an email.
Delete a user
DELETE https://<subdomain>.flowcase.com/api/v1/users/<user_id>
<user_id> is the internal Flowcase ID for the user.
Note that deleting a user means removing them from our system and that information can not be easily recovered.
User roles
Users can be given one of four basic roles plus some extra roles which grant additional permissions on top.
The base role is one of external, limited_access, consultant or internationalmanager. The extra roles are referencemanager, countrymanager, departmentmanager and bidmanager; pass them in extra_roles, where they are always layered on top of the consultant base role. For what each role can do, see User roles on the User Sync page.
Responses report the base role in role and the base role plus any extra roles together in roles.
When specifying the departmentmanager role when creating or updating a user you will also need to include the role_allowed_office_ids and/or role_allowed_tag_ids fields to specify which departments they have access to.
The role_allowed_tag_ids specifies one or more custom tags which this manager will have access to, making it possible to assign managers to users independent of how they are divided into offices in Flowcase. To assign these tags to users you can use the ensure_unique_custom_tag_ids_by_category attribute when creating or updating users, or use the Custom Tags API if you need more flexibility (like assigning more than one manager tag per user).
Example: update a user to be Department Manager
PUT https://<subdomain>.flowcase.com/api/v1/users/0123456789abcdef01234567
Request body
{
"user": {
"role": "consultant",
"extra_roles": ["departmentmanager"],
"role_allowed_office_ids": [
"00112233445566778899aabb",
"000111222333444555666777"
],
"role_allowed_tag_ids": [
"aaabbbcccdddeeefff000111",
"55556666777788889999aaaa"
]
}
}
What's next
- Try the create, find, read and update calls in the Integrations API reference, which lists every field and response code.
- Compare this API with the SCIM and CSV options in User Sync.
- Read a user's CV with the
default_cv_idfrom any user response: see CVs & CV Sections. - Manage the tags you assign with
ensure_unique_custom_tag_ids_by_categoryin Custom Tags. - Look up the
country_idandoffice_idvalues you need in Countries & Departments.