When to use this endpoint

Use after selecting all departments for a user. An empty string or encoded [] clears memberships; this operation replaces the full selection.

Authentication and permissions

Authenticate with signed API-key fields or a logged-in CRM session. Session requests use the dispatcher’s CSRF protection when configured; signed requests follow the API-key authentication flow.

Requires login and an owned tenant user. Ordinary self-profile edits are allowed; editing another user requires client administrator or explicit Users Edit permission. Protected membership fields require that permission even for self. Configured TeamAccess record scope and relationship checks remain in force. When hierarchy is enabled, the dispatcher additionally requires client administrator access for this relationship change.

The dispatcher applies configured TeamAccess user-record scope before the handler. An explicit target outside that scope returns an error; omitted targets use the current user for the scope check. Active/deleted filtering and additional target checks are described below.

Parameters

ParameterTypeRequiredDescription
idInteger stringYesTarget user ID in the authenticated tenant. Parsed with intval; this is a single-record operation, with no pagination or sort controls.
valsJSON array, native list, integer or CSV stringYesComplete positive department-ID selection. Empty string or [] clears it. IDs are validated, sorted and deduplicated; unknown departments and malformed/object lists are rejected.

Example request

$result = FM_api('User_setDepartments', [
	'id'=>'1042',
	'vals'=>json_encode(['18', '23']),
]);

Example response

{
  "ok": 1
}

Errors and unusual responses

ResponseCondition
{"error":"not logged in"}No authenticated tenant context is available. Invalid signed credentials can be rejected by the dispatcher before the handler runs.
{"error": "missing or invalid parameter: id"}id is omitted, null, or converts to an integer below 1.
{"error": "missing parameter: vals"}vals is omitted or null.
{"error": "user does not exist"}Tenant row is absent.
{"error": "no change needed"}The legacy stored/new representation comparison matches; this is returned as an error object.
{"error": "Client administrator access is required to change access relationships."}Hierarchy is enabled and the caller is not a client administrator.
{"error": "user does not exist"}No target user belongs to the authenticated account.
{"error": "only client admins or users with Users edit permission can edit other users"}Caller targets another user without explicit edit authority.
{"error": "Unable to save user changes. Check the saved state before retrying."}A checked write/transaction failed; inspect saved state before retrying, especially for separate global identity storage.
{"error":"department does not exist"}A selected department is absent; no memberships change.
{"error":"missing or invalid parameter: vals"}Membership input is malformed.
{"error":"invalid department membership data"}Stored reverse memberships cannot be safely represented.

Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.

Behaviour and edge cases

  • Validates all requested departments before changing either membership direction. The owned target user must exist; the handler does not filter departments by active state.
  • Compares semantic sorted membership sets across stored CSV/JSON formats, independent of the current CRM version. An unchanged selection returns the existing no change needed error without writes or history.
  • Preserves the version-compatible output format: non-2 CRM sessions save CSV, version 2 saves JSON string IDs. Reverse department membership is updated in the same format, accepting existing scalar/CSV/JSON lists.
  • The target user, reverse memberships and audit history are updated in one checked tenant transaction; malformed retained reverse memberships return invalid department membership data rather than silently discarding other users.
  • Hierarchy-enabled dispatcher checks can reject non-admin relationship edits or changes stranding outstanding Jobs. This call does not set the Parent Manager or change the department hierarchy.

Side effects

  • Updates tenant users/departments and their edit timestamps, stamps the user edited_uuid, invalidates the corresponding membership caches and logs departments updated. Does not mirror the department list to global identity storage.

See it in Fieldmotion

CRM1

On CRM1 Users, edit the department cell, or use User → Main → Departments. Filter User_setDepartments; both submit vals as JSON text.

CRM2

No direct production caller was found in CRM2. Its User layouts use the generic getRequestedDetails/updateData flow instead; do not assume that flow has the same validation or permissions as this legacy route.

Related endpoints