# Update membership type configuration

`PUT /api/configuration/membership-types/{all}`

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

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

## Overview

Sets the tags on a membership type, the earliest date a membership of that type may start, and its fixed end date — the calendar date a fixed-term membership type is configured to end on, instead of after its usual duration. These are the only three things this endpoint writes — a membership type's name, price and other properties are not editable here.

**`tags` is a full replacement; the two dates are not:**

- `tags` is the complete set of tags the membership type should carry. Tag mappings not present in
  your request are deleted, and `tags` is mandatory — so send the current tags back unless you
  intend to strip them. An empty array removes every tag.
- `earliestStartDate` and `fixedEndDate` each have three states. **Leave the field out** and the
  stored date is left unchanged. **Send `null`, an empty string or only whitespace** and the stored
  date is removed. **Send a date** and it replaces the stored one.

An earliest start date in the past is rejected, unless it is exactly the date already stored — which
is how a membership type with a historical date can be re-sent without hitting the validation. A
fixed end date before today is always rejected, even when it is the date already stored, so leave
`fixedEndDate` out when you are not changing it. "Today" is the current date in UTC. Only the date
part of either value is kept; any time component is discarded.

A fixed end date can be set only on an **up-front** membership type — one paid in full at purchase
that does not renew. It is rejected on a type that auto-renews, or whose payment method is Direct
Debit, BACS or recurring card payment (RCP). Removing a fixed end date is allowed on any type.

Validation happens before anything is written, so a rejected request changes nothing. Tag mappings
and the dates are then saved together.

On success the response is `204 No Content`, and the change is visible on the next read of tag groups
and of the membership types for every site this type is available at. Read the stored dates back with
[Get membership type by ID](get-membership-type-by-id.md).

## Endpoint

`PUT {base_url}/api/configuration/membership-types/{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` | string | Yes | Identifier of the membership type to configure, as returned by the membership type listing endpoints. If it matches nothing the request fails with `404 Unable to find Membership Type {id} to update.`, checked before the body. |

## Request body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `tags` | array of object | Yes | The complete set of tags the membership type should carry. Mandatory — it must be present, though an empty array is accepted and removes every tag. Existing mappings absent from this array are deleted and new ones are added, so read the current tags before calling. Where two of the resolved tags belong to the same tag group and that group does not allow multiple tags, the request fails with `400 Invalid update request, more than one tag is specified for a tag group that does not allow multiple tags.` |
| `tags[].id` | integer (int32) | No | Numeric identifier of the tag. Give either `id` or `key` for each entry — an entry with neither fails with `400 All tags must contain either Id or Key property.`. The same id must not appear twice (`Unable to update Membership Type with tags as the tag ID(s) {ids} are duplicated.`), and you must not name the same underlying tag once by id and once by key. An id that does not exist is only caught when the change is saved, surfacing as `400 All tags must have a valid Id or Key.` |
| `tags[].key` | string | No | Text key of the tag, used instead of `id` — it is resolved to the tag's identifier. Maximum 50 characters. Only consulted for entries that have no `id`, so sending both means the `key` is ignored. Keys must be unique across the array (`Unable to update Membership Type with tags as the tag Key(s) {keys} are duplicated.`), and a key that matches no tag contributes nothing rather than raising its own error, which can silently drop a tag you meant to keep. |
| `earliestStartDate` | string (date-time) | No | The earliest date a membership of this type may start; memberships cannot be backdated before it. Only the date part is kept — any time of day you send is discarded. Leave the field out to keep the stored date; send `null`, `""` or whitespace to remove it. A date before today is rejected with `400 EarliestStartDate cannot be in the past`, **except** when it is identical to the date already stored, so an existing historical value can be re-sent unchanged. |
| `fixedEndDate` | string (date-time) | No | The calendar date this membership type is configured to end on, which makes it a fixed-term type rather than one that runs for its usual duration. Only the date part is kept. Leave the field out to keep the stored date; send `null`, `""` or whitespace to remove it, which is accepted on any membership type. A date you send must be a real calendar date (`2027-02-29` is rejected, `2028-02-29` is accepted), must be today or later (`400 FixedEndDate cannot be in the past`, even if it is the date already stored), and must not be earlier than the earliest start date (`400 FixedEndDate cannot be earlier than EarliestStartDate`). That check uses the `earliestStartDate` in the same request when you send one — including `null`, which removes the check — and otherwise the stored earliest start date; the same day is allowed. A date is rejected on a membership type that auto-renews or is paid by Direct Debit, BACS or recurring card payment (`400 FixedEndDate can only be set on up-front membership types`). |

## Sample request

```bash title="cURL"
curl -X PUT '{base_url}/api/configuration/membership-types/{all}' \
  -H 'Authorization: Bearer {accessToken}' \
  -H 'X-Use-SSO: true' \
  -H 'Content-Type: application/json' \
  -d '{
  "tags": [
    {
      "id": 12345,
      "key": "string"
    }
  ],
  "earliestStartDate": "2026-11-01T00:00:00Z",
  "fixedEndDate": "2027-10-31T00:00:00Z"
}'
```

## Errors

| Status | Meaning | When |
|--------|---------|------|
| `400` | Bad request | `tags` is missing from the body, or `tags[].key` exceeds 50 characters. These are validation failures, so the body is a validation problem document rather than a plain string. |
| `400` | Bad request | An entry in `tags` has neither `id` nor `key` — `All tags must contain either Id or Key property.` |
| `400` | Bad request | `tags` names the same tag twice — `Unable to update Membership Type with tags as the tag ID(s) {ids} are duplicated.`, `… the tag Key(s) {keys} are duplicated.`, or `Unable to update Membership Type with tags as the tag Key(s) or ID(s) are duplicated.{details}` when an id and a key resolve to the same tag. |
| `400` | Bad request | Two resolved tags belong to a tag group that does not allow multiple tags — `Invalid update request, more than one tag is specified for a tag group that does not allow multiple tags.` |
| `400` | Bad request | A tag id does not exist — `All tags must have a valid Id or Key.` |
| `400` | Bad request | `earliestStartDate` is before today and differs from the value already stored — `EarliestStartDate cannot be in the past`. |
| `400` | Bad request | `fixedEndDate` is not a real calendar date — `2027-02-31`, `2027-02-29`, `2027-13-01` — or is not a date at all, such as a number, `true` or arbitrary text. The body is a validation problem document (`application/problem+json`) with an `errors` map keyed by field name. |
| `400` | Bad request | `fixedEndDate` is before today — `FixedEndDate cannot be in the past`. |
| `400` | Bad request | `fixedEndDate` is earlier than the earliest start date sent in the request or, when none is sent, the one stored — `FixedEndDate cannot be earlier than EarliestStartDate`. |
| `400` | Bad request | `fixedEndDate` is a date and the membership type auto-renews or is paid by Direct Debit, BACS or recurring card payment — `FixedEndDate can only be set on up-front membership types`. |
| `404` | Not found | No membership type matches the path identifier — `Unable to find Membership Type {id} to update.` Checked first, so it masks any problem with the body. |
| `500` | Internal server error | Any other unexpected server-side failure. No detail is returned. |
