# Update member contact details using JSON Patch

`PATCH /api/members/{memberId}/contact-details`

- **Products:** Operator (`FOH`), Consumer (`CONSUMER`) (any one of these products, not all)
- **Features:** Online Bookings (`ONLINEBOOK`), Online Joining (`ONLINEJOIN`), Front of House Generic Access (`FOHGENERIC`) (any one of these features, not all)

HTML version: [Update member contact details using JSON Patch](https://support.gladstonesoftware.cloud/reference/members/update-member-contact-details-using-json-patch)

## Overview

Updates a member's email addresses and telephone numbers using a JSON Patch document (RFC 6902).

This is a genuine partial update. Your operations are applied to the member's current contact details, and the result is then validated and saved — so anything you do not name in an operation keeps its existing value. There is no `PUT` equivalent; this endpoint is the only way to change these fields.

A member has exactly five fixed contact slots, not a growable list:

| Path | Holds |
|---|---|
| `/email1/emailAddress` | Home email address — the member's main email. |
| `/email1/isPrimary` | Whether the home email is the primary email (boolean). |
| `/email2/emailAddress` | Work email address. |
| `/email2/isPrimary` | Whether the work email is the primary email (boolean). |
| `/telephone1/number` | Home telephone number. |
| `/telephone1/isPrimary` | Whether the home number is the primary number (boolean). |
| `/telephone2/number` | Work telephone number. |
| `/telephone2/isPrimary` | Whether the work number is the primary number (boolean). |
| `/mobile/number` | Mobile telephone number. |
| `/mobile/isPrimary` | Whether the mobile number is the primary number (boolean). |
| `/inheritPrimaryMembersEmail` | Whether this member takes their email from the primary member they are linked to (boolean). |

Because the slots are fixed, `add` and `replace` behave identically — both overwrite the slot. `add` never creates a third email or a fourth phone number.

Three rules cause most rejections:

1. **Only one primary at a time.** At most one of `email1`/`email2` may end up primary, and at most one of `telephone1`/`telephone2`/`mobile`. The check runs on the merged document, so setting a new primary without clearing the old one in the same request fails with `400`.
2. **Clearing a value requires the slot to be non-primary.** Blanking an email or a number while its `isPrimary` is `true` is rejected. Set `isPrimary` to `false` in the same patch document.
3. **A home email is mandatory for most members.** Blanking `/email1/emailAddress` is rejected unless the member is under the tenant's configured age for online accounts, or `/inheritPrimaryMembersEmail` is `true`.

Linked members are permitted — a token issued for a member linked to `{memberId}` may call this endpoint.

## Endpoint

`PATCH {base_url}/api/members/{memberId}/contact-details`

`{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 |
|------|------|----------|-------------|
| `memberId` | integer (int32) | Yes | The member whose contact details are updated. Must match the member id in your access token, or be a member linked to it. |

## Request body

The body is a JSON array of patch operations, applied in order.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `[].op` | string | Yes | The operation to perform. `replace` and `add` both overwrite the slot named by `path`; `remove` clears it, which for a string slot means an empty value and therefore triggers the primary and home-email rules above. `move`, `copy` and `test` are also accepted by the patch parser. An unrecognised operation returns `400 The contact details don't match with the required fields and value types.` |
| `[].path` | string | Yes | The contact slot to change, as a JSON Pointer — one of the paths listed in the Overview, such as `/email1/emailAddress` or `/mobile/isPrimary`. Use the camelCase form shown. A path that does not exist on the contact-details document returns `400 The contact details don't match with the required fields and value types.` |
| `[].value` | string | No | The new value for the slot. Required for `add` and `replace`, ignored for `remove`. The JSON type must match the slot: a string for `emailAddress` and `number`, a real JSON boolean (`true`/`false`, not `"true"`) for every `isPrimary` and for `inheritPrimaryMembersEmail`. Email addresses are limited to 255 characters and telephone numbers to 50; email must contain exactly one `@` that is neither the first nor the last character. Telephone numbers are not format-checked. |
| `[].from` | string | No | The source pointer for `move` and `copy` operations. Leave it out for `add`, `replace` and `remove`. |

## Sample request

```bash title="cURL"
curl -X PATCH '{base_url}/api/members/{memberId}/contact-details' \
  -H 'Authorization: Bearer {accessToken}' \
  -H 'X-Use-SSO: true' \
  -H 'Content-Type: application/json' \
  -d '[
  {
    "op": "replace",
    "path": "/email1/emailAddress",
    "value": "new.address@example.com"
  },
  {
    "op": "replace",
    "path": "/mobile/number",
    "value": "07123456789"
  },
  {
    "op": "replace",
    "path": "/mobile/isPrimary",
    "value": true
  },
  {
    "op": "replace",
    "path": "/telephone1/isPrimary",
    "value": false
  }
]'
```

## Errors

A successful call returns `204 No Content`. Validation runs on the merged document, so an error message can name a field you did not patch.

| Status | Meaning | When |
|--------|---------|------|
| `400` | Bad request | The document could not be applied — an unknown `path`, an unsupported `op`, or a `value` whose JSON type does not fit the target: `The contact details don't match with the required fields and value types.` |
| `400` | Bad request | An email address is malformed: `The email address for 'Email1' does not have the right format. Example: test@mail.com` (likewise `'Email2'`) |
| `400` | Bad request | Two emails ended up primary: `There cannot be more than one primary contact email`; two or more numbers ended up primary: `There cannot be more than one primary contact number` |
| `400` | Bad request | A number was blanked while still marked primary: `Updating a number with an empty string requires primary to be false` |
| `400` | Bad request | An email was blanked while still marked primary: `Updating a email with an empty string requires primary to be false` |
| `400` | Bad request | The member is old enough to need an online account and has no home email left: `A member must have a home email address` |
| `400` | Bad request | `inheritPrimaryMembersEmail` is `true` but an email address is still set: `A member that is inheriting a primary members email can not supply an email as well` |
| `400` | Bad request | The email now belongs to someone else: `A member with email address {email} already exists`. This check is skipped for members still pending confirmation. |
| `400` | Bad request | A length limit was breached — `Email address cannot be longer than 255 characters`, `Number cannot contain more than 50 characters`. Returned as a model-state object rather than a plain string. |
| `404` | Not found | No member exists with that id: `The member with ID {memberId} does not exist` |
| `500` | Internal server error | Saving the change failed, or another unexpected server-side failure occurred. No detail is returned in the body. |
