# Update User Data

Change one trader's profile, community roles or broker identifier, sending only the fields that change.

- Endpoint: `POST https://api.returning.ai/v1/users/update`
- Section: Users and data / Users
- Authentication: `Authorization: Bearer <API_KEY>` (Community API key)
- Permission: `manageUser` (Role changes also need bulkUpdateUser)
- Retries: No Idempotency-Key; read back before repeating
- Guide: hand-written
- Verified: live, 2026-09-27
- Last updated: 26 Sep 2026
- Web page: https://docs.returning.ai/api-reference/users/update-user-data

## When to use this

- A trader changes their name, email or phone on your platform.
- You add, remove or replace a trader's community roles, such as `VIP`.
- You need to replace a trader's broker identifier. This is the only supported endpoint for that.

**Instead:** Use [Create User](https://docs.returning.ai/api-reference/users/create-user.md) instead to add a trader who does not exist yet.

**Identifier changes:** Send an identifier change on its own. Combined with a profile or role change, it is rejected and nothing is written.

## Authentication

- Header: `Authorization: Bearer <API_KEY>`
- Permission: `manageUser`

Profile and identifier changes need `manageUser`. A request that includes `updates.roles` needs both `manageUser` and `bulkUpdateUser`. Keep the Community API key on your server.

## Request

### Headers

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | `string` | Yes | Community API key with `manageUser`, plus `bulkUpdateUser` for role changes. (`Bearer <API_KEY>`) |
| `Content-Type` | `string` | Yes | Request body format. (`application/json`) |

### Body

`identifier` finds the trader and `updates` holds the changes. Send only the properties that change. To replace the broker identifier, send `custom_user_identifier` as the only property in `updates`, in a request of its own.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `identifier` | `object` | Yes | Selects the trader to change. |
| `identifier.type` | `string` | Yes | How `value` identifies the trader. (`platform_user_id`, `username`, `email`, `custom_user_identifier`) |
| `identifier.value` | `string \| number` | Yes | The identifier value to match. |
| `updates` | `object` | Yes | Only the changes you want to make. (At least one property) |
| `updates.firstname` | `string` | No | The trader's first name. |
| `updates.lastname` | `string` | No | The trader's last name. |
| `updates.email` | `string` | No | The trader's email. It must not belong to another trader. (Email format) |
| `updates.phone` | `string` | No | The trader's phone number. |
| `updates.roles` | `object` | No | A role change. |
| `updates.roles.operator` | `string` | Yes | `add` and `subtract` are safe to repeat. `overwrite` replaces the trader's changeable roles in this community. (`add`, `subtract`, `overwrite`) |
| `updates.roles.names` | `string[]` | Yes | Exact, case-sensitive role names in this community. `all` and `@all` cannot be changed. (Min 1 item; unique) |
| `updates.custom_user_identifier` | `string \| number` | No | The new broker identifier. Locate the trader by `platform_user_id` or `username`. (Must be the only property in `updates`) |

### Example request

```bash
curl --request POST \
  --url https://api.returning.ai/v1/users/update \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "identifier": {
      "type": "platform_user_id",
      "value": "3247779"
    },
    "updates": {
      "firstname": "Sample",
      "roles": {
        "operator": "add",
        "names": ["VIP"]
      }
    }
  }'
```

## Response

A `200` returns the trader after the update in `data`. `roles` is present only when the request changes roles. Read the trader back with Get User Data to confirm.

### Response fields

| Field | Type | Presence | Description |
| --- | --- | --- | --- |
| `status` | `string` | always | Result of the request. (`success`) |
| `code` | `string` | always | Machine-readable result code. (`USER_UPDATED`) |
| `message` | `string` | always | Human-readable summary. Do not branch on it. |
| `data` | `object` | always | The trader after the update. |
| `data.id` | `string` | always | Platform user ID. Store it as a string and never do arithmetic on it. (Decimal digits) |
| `data.firstname` | `string` | always | The stored first name. |
| `data.lastname` | `string` | always | The stored last name. |
| `data.email` | `string` | always | The stored email. (Email format) |
| `data.phone` | `string` | always | The stored phone number. |
| `data.custom_user_identifier` | `string \| number` | always | The trader's broker identifier. (Nullable) |
| `data.roles` | `string[]` | when roles change | The trader's roles, returned when the request changes roles. |

### Example response (200)

```json
{
  "status": "success",
  "code": "USER_UPDATED",
  "message": "User updated successfully",
  "data": {
    "id": "3247779",
    "firstname": "Sample",
    "lastname": "Trader",
    "email": "trader@example.com",
    "phone": "15551234567",
    "custom_user_identifier": "<brokerCustomerId>",
    "roles": ["@all", "VIP"]
  }
}
```

## Errors

Errors from the API key check carry the code in `meta.code`, except the `401` for a role change without `bulkUpdateUser`, which has only a `message`. Other coded errors carry it in `code`. A `400` writes nothing, so correct the request and send it again. A malformed request, such as a bad identifier type or role operator, returns `400` with a `message` and a `detail` list explaining what's wrong, and no top-level `code`.

### Fix the request

| Status | Code | What to do |
| --- | --- | --- |
| 400 | - | The body failed validation. There is no `code`; `detail` names the field. Common causes: - `identifier.type` is not one of the four types, or `roles.operator` is not `add`, `subtract` or `overwrite`. - `updates` is empty, or `custom_user_identifier` is empty. - `roles.names` is empty or includes `all` or `@all` (`Default roles cannot be updated`). - You looked the trader up by `email` and sent a new `email`, or by `custom_user_identifier` and sent a new `custom_user_identifier`. Look the trader up by platform user ID or username instead. |
| 401 | - | The request changes `roles` and the key has `manageUser` but not `bulkUpdateUser`. The body is only `{"message": "Your api key does not have permission to access this action"}`, with no code. Add `bulkUpdateUser` to the key. |
| 400 | `INVALID_USER_UPDATE` | The `message` names the rule: - `Custom user identifier is not configured for this community`: set up an active identifier field before sending `custom_user_identifier`. - `Custom user identifier field is not configured correctly`: ask Returning.AI to check the identifier field's setup. - `<Field> - Identifier is required`: send a non-empty identifier value. |
| 400 | `MIXED_IDENTIFIER_UPDATE_NOT_SUPPORTED` | The identifier change was combined with another update. Nothing was written; split it into two requests. |
| 400 | `ROLE_NOT_FOUND` | A role name did not match exactly. Role names are case-sensitive. |
| 400 | `ROLE_NAME_AMBIGUOUS` | More than one role matched, so nothing was written. Use the exact role name. |
| 401 | `AUTHENTICATION_REQUIRED` | The key is missing, malformed, invalid or expired. Send `Authorization: Bearer <API_KEY>` with a current key. |
| 403 | `API_KEY_PERMISSION_DENIED` | The key lacks `manageUser`. Add the permission in Settings > Integration > API Keys. |

### Fix the data

| Status | Code | What to do |
| --- | --- | --- |
| 404 | `USER_NOT_FOUND` | No active trader in this community matches. Check the identifier. |
| 409 | `USER_EMAIL_CONFLICT` | The new email belongs to another trader (message: `Email already exists`). Reconcile the two accounts first. |
| 409 | `USER_IDENTIFIER_CONFLICT` | The new identifier belongs to another trader (message: `<Field name> - Identifier is already used by another user`, or `<Field name> - Duplicate users found`). Reconcile the two accounts first. |

### Retry with backoff

| Status | Code | What to do |
| --- | --- | --- |
| 500 | `USER_UPDATE_FAILED` | The update failed unexpectedly. Read the trader back with Get User Data before you try again. |
| 503 | `USER_IDENTIFIER_NOT_READY` | Identifier lookup is not ready. Retry later with backoff, or locate the trader by platform user ID. |

### Do not retry

| Status | Code | What to do |
| --- | --- | --- |
| 500 | `USER_UPDATE_RECONCILIATION_REQUIRED` | The identifier change is unclear. Stop automatic retries and read the trader back before any other update. |

**Retries:** Update User Data does not accept an `Idempotency-Key`. After a timeout, read the trader back with Get User Data before you repeat any update. Over the [rate limit](https://docs.returning.ai/how-it-works.md#rate-limits), requests return `429`; wait for the window to reset, then retry.

## Next step

- [Get User Data](https://docs.returning.ai/api-reference/users/get-user-data.md): `POST /v1/users/info`. Read the trader back to confirm the new profile, roles or identifier.
