> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qobra.co/llms.txt
> Use this file to discover all available pages before exploring further.

# update_user_attribute_values

> Set some of a user's attribute values, all or nothing. An attribute left out keeps its value.

Set some of a user's attribute values, and return the ones that changed.

Only the attributes sent are written. Read the user's current values with
[`get_user`](https://docs.qobra.co/mcp_documentation/tools/get_user), and each attribute's type and
the labels a picklist accepts with
[`list_user_attributes`](https://docs.qobra.co/mcp_documentation/tools/list_user_attributes). Every
value is checked before the first write, so a call writes all of its values or
none; sending values the user already holds changes nothing, so the same call
can be sent twice.

An amount keeps the currency the user holds it in, as in the Qobra web app. A
unique attribute refuses a value another user already holds, and changing one
re-matches in the background the records of the data tables that match their
users on it.

On a user synced from an HRIS, a value written over a synced attribute is kept
as an overwrite: later syncs leave it in place, and Qobra keeps the synced value
beside it. Sending the synced value back, or null, cancels the overwrite.

No statement is recalculated by this call, as after an edit in the web app: a
calculation reading these attributes picks the change up the next time it runs.

The call is refused, with a message naming the problem, when the user is
archived, when an attribute is unknown or listed twice, when a value does not
match its attribute's type or picklist options, or when a unique attribute is
given a value another user already holds.

Requires write permission on users. Available only where the Qobra write tools
beta is enabled. Every write is recorded in the audit trail as the `Qobra MCP`
agent.

```json Example arguments theme={null}
{
  "user_id": "jane.doe@acme.com",
  "values": [
    { "attribute_id": "665f1c2e8a4b3d0012a7e9f1", "value": "Enterprise" },
    { "attribute_id": "665f1c2e8a4b3d0012a7e9f2", "value": "2024-09-01" }
  ]
}
```

## Parameters

> **Body**
>
> **user\_id** `string` *required*
>
> Id of the user whose attribute values to set — the id list\_users returns.
> An exact email is accepted too.
>
> **values** `object[]` *required*
>
> The values to write, one per attribute. An attribute left out keeps its
> value.
>
> **object properties**
>
> **attribute\_id** `string` *required*
>
> Id of the attribute — the `id` list\_user\_attributes returns. Never a
> name or a key.
>
> **value** `string | number | boolean | string[]` *required*
>
> The user's new value, in the shape get\_user serves it: a number for
> amount / float / percentage (a percentage is the ratio, 0.8 for 80%),
> true/false for bool, an ISO date (`2026-03-14`) for date, text for
> string, one option label for picklist, a list of option labels for
> multipicklist, and a user id or email for user. null empties the
> value.

## Response

> **Body**
>
> **user** `object`
>
> The user whose attribute values the call set.
>
> **object properties**
>
> **id** `string`
>
> **email** `string`
>
> **name** `string`
>
> **attributes** `object[]`
>
> Every attribute whose value the call changed, with the value the user now
> holds, in the shape get\_user serves it. Empty when every value sent was
> already the user's, which is how a repeated call reads as the no-op it
> was.
>
> **object properties**
>
> **id** `string`
>
> Id of the attribute this value belongs to — the id
> list\_user\_attributes returns, so a value maps back to its definition
> even when two attributes share a display name.
>
> **name** `string`
>
> **value** `any`
>
> **currency** `string`
>
> Currency code of an amount value (EUR, USD…); null on every other
> type.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.