# Create a new linked member for a primary member

`POST /api/members/{memberId}/linked-members`

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

HTML version: [Create a new linked member for a primary member](https://support.gladstonesoftware.cloud/reference/members/create-a-new-linked-member-for-a-primary-member)

## Overview

Creates a brand-new member from scratch and attaches them to an existing primary member in a single call. Reach for this when adding someone who has no record yet — a child or partner being added to an existing account. If the person already exists as a member, do not use this endpoint; link the existing records with [Create member links](create-member-links.md), or have them exchange a request through [Send link request to another member](send-link-request-to-another-member.md).

This is a sequence of steps, not a single write, and it is **not idempotent** — every call creates another new member. It runs five steps in order: read the primary member's profile and reject the call if the primary is below the age of consent; derive the new member's price level; create the member; link them to the primary; apply the primary's shareable memberships; and finally confirm the new member. On success it returns `201 Created` with a body carrying the new member's id as `memberId` — capture it, because it is the only place you are given it.

When a step fails, the endpoint unwinds the steps that already succeeded, and how far it unwinds depends on where it broke. A failure creating the member leaves nothing behind. A failure linking rolls back the new member's account. A failure applying memberships unlinks the pair and then rolls back the account. A failure confirming removes the applied memberships, then unlinks, then rolls back the account.

**There is one hole in that unwinding you must handle.** If the confirmation step fails and the membership-removal part of the rollback also fails, the endpoint returns that rollback failure straight to you as a `404` or `400`, and the remaining unlink and account rollback never run. You are left with a new member who exists, is linked to the primary, holds shared memberships, and is still pending confirmation — a state no single retry will clear, and a repeat call will create a second member rather than repair the first. Treat any non-`201` response as "state unknown": look up the primary member's linked members before deciding what to do, and clean up with [Remove shared membership access between linked members](remove-shared-membership-access-between-linked-members.md) and [Unlink secondary member from primary member](unlink-secondary-member-from-primary-member.md) if a partial record survived.

Three fields do not behave the way their presence in the request suggests. `siteId` and `priceLevelId` are both overwritten by the endpoint before the member is created, so anything you send in them is discarded. `pendingConfirmation` must be `true`, because the last step confirms the member and the confirm operation rejects a member that is not pending.

Note that this endpoint only requires a member id in the route — it does not itself check that the token belongs to `memberId`. A `403` here comes from one of the individual steps refusing the operation, not from an ownership check on `memberId`.

## Endpoint

`POST {base_url}/api/members/{memberId}/linked-members`

`{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 existing member the new person is attached to, who becomes the primary of the pair. This member's profile supplies the site the new member is created at and, through their first membership flagged to apply to links, the price level the new member is given. They must be at or above the configured age of consent — a junior primary is rejected with `400` and the message `You cannot link a new member to a junior member.` |

## Request body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `firstName` | string | Yes | The new member's given name, stored on their profile. Must be between 2 and 25 characters; omitting it fails with `First name is required` and a length outside that range fails with `First name cannot be less than 2 characters or more than 25 characters`. |
| `lastName` | string | Yes | The new member's family name, stored on their profile. Must be between 2 and 25 characters; omitting it fails with `Last name is required` and a length outside that range fails with `Last name cannot be less than 2 characters or more than 25 characters`. |
| `dateOfBirth` | string (date-time) | Yes | The new member's date of birth. It does more than populate the profile: it decides whether `email` is required or forbidden, by comparison against the configured age at which a member may hold an online account, and it is one of the inputs used to resolve the new member's price level. Cannot be a future date — that fails with `Date of Birth cannot be in the future` — and omitting it fails with `Date of Birth is required`. |
| `email` | string | No | The new member's email address. Whether you may send it is decided entirely by `dateOfBirth`. For a member at or above the age at which an online account is permitted the field is effectively required — omit it and the call fails with `The member is missing the email address.` For a member below that age it must be omitted — send one and the call fails with `Member is below the age of having an online account and so no email address should be provided.` When sent it must be under 256 characters and a valid email address, or you get `The supplied email must be less than 256 characters long.` and `The email address "{email}" is not a valid email address.` respectively. All of this is checked before any member record is created, so a rejection here leaves nothing behind. |
| `siteId` | string | No | Ignored. Whatever you send is replaced with the site taken from the primary member's profile, so the new member is always created at the primary's site. There is no way to place a linked member at a different site through this endpoint. |
| `priceLevelId` | string | No | Ignored. Whatever you send is replaced with a price level resolved from the primary member's first membership flagged to apply to links, together with the new member's `dateOfBirth` and the inherited site. If that lookup fails the whole call fails before the member is created. |
| `pendingConfirmation` | boolean | No | Whether the member is created provisionally, pending a later confirmation. Send `true`: the endpoint's final step confirms the new member, and confirming a member that is not pending is rejected — so a member created with this set to `false` or omitted will fail at that last step and be rolled back, having been created, linked and given memberships first. You do not need to call [Confirm a previously unconfirmed member creation](confirm-a-previously-unconfirmed-member-creation.md) yourself; this endpoint does it for you. |

## Sample request

```bash title="cURL"
curl -X POST '{base_url}/api/members/{memberId}/linked-members' \
  -H 'Authorization: Bearer {accessToken}' \
  -H 'X-Use-SSO: true' \
  -H 'Content-Type: application/json' \
  -d '{
  "firstName": "string",
  "lastName": "string",
  "dateOfBirth": "2026-08-14T19:00:00Z",
  "email": "member@example.com",
  "siteId": "string",
  "priceLevelId": "string",
  "pendingConfirmation": true
}'
```

## Sample response

```json title="201 Created"
"string"
```

## Errors

| Status | Meaning | When |
|--------|---------|------|
| `400` | Bad request | The body fails validation: a missing or wrongly sized `firstName` or `lastName`, or a missing or future `dateOfBirth`. The response carries the specific message listed against each field above. |
| `400` | Bad request | The `email` rules for the new member's age are broken — missing when required, supplied when the member is below the age for an online account, longer than 255 characters, or not a valid address. Checked first, so nothing is created. |
| `400` | Bad request | The primary member named by `memberId` is below the configured age of consent. The message reads `You cannot link a new member to a junior member.` A junior member cannot have linked members of their own. |
| `400` | Bad request | One of the steps was rejected, and its message is returned verbatim. This is also returned when the rollback after a failed confirmation could not remove the new member's memberships — in that case the message describes the *rollback* failure, and a partially created member survives. |
| `403` | Forbidden | One of the steps refused the operation for this caller, and its message is returned. The endpoint itself does not check the token against `memberId`. |
| `404` | Not found | A record needed by one of the steps could not be found, and that step's message is returned — for example the primary member does not exist. Also returned when the post-confirmation rollback could not find the memberships it was trying to remove, which leaves the new member created, linked and unconfirmed. |
| `409` | Conflict | One of the steps reported a conflicting state, and its message is returned — for example the primary member has already reached the maximum number of linked members. |
| `422` | Unprocessable entity | One of the steps could not be processed, and its message is returned, most often when the shared memberships could not be written to the new member. The rollback then unlinks the pair and rolls back the new account. |
| `500` | Internal server error | An unexpected server-side failure: part of the platform needed for one of the steps was unavailable, or a step failed with a status other than those above. The new member may or may not exist — check before retrying, since a retry creates another member. |
