# Update user field configuration

`PUT /api/configuration/user-fields/{all}`

- **Products:** Operator (`FOH`)
- **Features:** Front of House Generic Access (`FOHGENERIC`)

HTML version: [Update user field configuration](https://support.gladstonesoftware.cloud/reference/configuration/update-user-field-configuration)

## Overview

Updates a user field definition. User fields are the custom, per-account attributes you can hold against a member beyond the standard profile — a membership number from a legacy system, a locker number, a consent date.

**This is a full replacement, not a partial update.** `isActive`, `sortOrder`, `description` and `type` are all written on every call, and every one of them is required, so there is no way to change just one. `defaultValue` and `options` are rewritten too: omitting `defaultValue` clears the field's default, and any option not present in `options` is deleted along with its translations.

**A field that any member already has a value for is locked.** Once one member holds a value, you can no longer change the field's `type`, nor add, remove or rename its options — attempting either fails with `400` and `User field is locked, type or options cannot be modified.` You can still change `description`, `sortOrder` and `isActive`. Send the field's current `type` and `options` back unchanged on those calls.

Two more things worth knowing before you send anything:

- **`sortOrder` must be unique across all user fields.** There is no auto-assignment on update; you have to pick a free number yourself.
- **Renaming an option orphans existing member data.** A member's value is held as the option's description text, not its id, so changing a description leaves existing values pointing at a label that no longer exists. This is also why the lock exists.

Read the current definition from [List user field configurations](get-all-user-field-configurations.md) and send it back with your change applied. A successful update returns `204 No Content`.

## Endpoint

`PUT {base_url}/api/configuration/user-fields/{all}`

`{base_url}` is the environment URL issued to your integration. See [Authenticating with Gladstone APIs](../../guides/authenticating-with-gladstone-apis.md).

## Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | integer (int32) | Yes | The user field's identifier, as returned in `[].id` by [List user field configurations](get-all-user-field-configurations.md). Values above 32767 never match a field. An id with no matching field fails with `404`. |

## Request body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `isActive` | boolean | Yes | Whether the field is in use — set `false` to retire it without deleting it or losing the values members already hold. Required on every call, so resend the current value when you are changing something else. |
| `sortOrder` | integer (int32) | Yes | Where the field appears relative to other user fields; lower sorts first. Required, and must be between 0 and 32767. **It must be unique across all user fields** — reusing a number another field already has fails with `User field sort order is not unique.` Keeping your own value is fine; the check ignores the field being updated. |
| `description` | string | Yes | The field's label, as shown to staff and members. Required and limited to 25 characters, which is short — plan the wording before you build a UI around it. Written on every call, so resend the current value if you are not changing it. |
| `type` | string (enum) | Yes | One of: `Free_Format`, `Options`, `Date`, `Numeric`, `Currency`, `Hyperlink`, `User`, `Member`. |
| `defaultValue` | string | No | The value a member's field starts at when no value has been set. Omitting it or sending null clears any stored default. Its accepted shape depends on `type`, and it is not always a string despite the schema: `Free_Format`, `Options` and `Hyperlink` take a string, `Numeric` and `Member` take a number, `Currency` takes a decimal number with no currency symbol, `User` takes an object of the form `{"isCurrentUser": true}` or `{"userId": "…"}` — never both, which is rejected — and `Date` takes an object with `dayType`, `monthType`, `day`, `month` and `year`, all five of which must be present. For `Options` the value must exactly match one of the `options[].description` values you are sending, or the call fails with `DefaultValue option {value} is not one of the given option descriptions.` For `Member` the id must belong to a real member, or the call fails with `404`. Anything that will not parse for its type fails with `Failed to parse {value} correctly for its type of {type}.` |
| `options` | array of object | No | The complete list of selectable values, and only meaningful when `type` is `Options`. Required in that case — an empty or absent array fails with `User field with Options type must have options specified.` For every other type it must be absent or empty, or the call fails with `User field of non-Options type may not have options specified.` The list is absolute: options you leave out are deleted along with their translations, and switching the field to a non-`Options` type deletes all of them. On a locked field the list must match what is stored exactly, by id and by description. |
| `options[].id` | integer (int32) | No | The option's identifier within this field, as returned by [List user field configurations](get-all-user-field-configurations.md). Send `0`, or omit it, to add a new option — the next free id is allocated for you. Send an existing id to rename that option. An id greater than zero that does not already belong to this field fails with `Option ID {id} does not already exist on this user field.` Ids are scoped to the field, so option `1` exists separately on every field. |
| `options[].description` | string | Yes | The option's display text, and also the value stored against members who select it. Required and limited to 50 characters. Because member values are matched on this text rather than on `id`, changing it does not migrate existing member data — which is why the field locks as soon as any member has a value. |

## Sample request

```bash title="cURL"
curl -X PUT '{base_url}/api/configuration/user-fields/{all}' \
  -H 'Authorization: Bearer {accessToken}' \
  -H 'X-Use-SSO: true' \
  -H 'Content-Type: application/json' \
  -d '{
  "isActive": true,
  "sortOrder": 1,
  "description": "string",
  "type": "Free_Format",
  "options": [
    {
      "id": 12345,
      "description": "string"
    }
  ]
}'
```

## Errors

| Status | Meaning | When |
|--------|---------|------|
| `400` | Bad request | A required field is missing, `description` is over 25 characters, `sortOrder` is outside 0–32767, or `type` is not one of the listed values. The body is a validation error object keyed by field name; an unrecognised type gives `The user field type is required to be a non-empty and valid value`. |
| `400` | Bad request | At least one member already holds a value for this field and you changed `type`, or added, removed or renamed an option — `User field is locked, type or options cannot be modified.` |
| `400` | Bad request | Another user field already uses that `sortOrder` — `User field sort order is not unique.` |
| `400` | Bad request | `type` is `Options` but `options` is empty or absent — `User field with Options type must have options specified.` |
| `400` | Bad request | `type` is not `Options` but `options` has entries — `User field of non-Options type may not have options specified.` |
| `400` | Bad request | An `options[].id` above zero does not belong to this field — `Option ID {id} does not already exist on this user field.` |
| `400` | Bad request | `defaultValue` does not fit `type` — `Failed to parse {value} correctly for its type of {type}.` For `Options` the message is `DefaultValue option {value} is not one of the given option descriptions.` instead. |
| `404` | Not found | No user field has that `id` — `User field {id} was not found.` |
| `404` | Not found | `type` is `Member` and the `defaultValue` member id does not exist — `Member ID {id} was not found.` |
| `500` | Internal server error | An unexpected server-side failure. The response body is empty. |
