# Create member personalisation

`POST /api/members/{memberId}/personalisation`

- **Success:** `201 Created`
- **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: [Create member personalisation](https://support.gladstonesoftware.cloud/reference/members/create-member-personalisation)

## Overview

Stores one preference against a member as a key and value pair, and returns the id of the record it created. A member may hold at most one record per key: creating a second of the same key returns `409`, and you change an existing preference with `PUT {base_url}/api/members/{memberId}/personalisation/{personalisationId}` rather than by posting again.

In practice there is one usable key today. The endpoint accepts `Language` and rejects every other key with `The personalisation type {typeKey} is not currently supported.`, even where the key is configured as a personalisation type for your tenant — the type must both exist and be one the endpoint can validate. If all you need is the member's language at sign-up, you can skip this call entirely and send `memberLanguage` on `POST {base_url}/api/members/profile`, which creates the same record as part of creating the member.

Watch the language value. It is checked against the tenant's list of allowed languages and, if it is not on that list, it is quietly replaced with `en-GB` and saved — you get a `201` and an id back, for a value you did not send. Read the record back with `GET {base_url}/api/members/{memberId}/personalisation/{personalisationKey}` if the stored value matters to you.

## Endpoint

`POST {base_url}/api/members/{memberId}/personalisation`

`{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 the preference is stored against. Must be greater than zero: `0` (the reserved non-member id) and `-999` (a purged member) are rejected with `{memberId} is an invalid member ID`. If your access token identifies a member, this must be that same member — unlike most profile endpoints, this one does not accept a linked member's id and returns `403` for one. |

## Request body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `memberId` | integer (int32) | No | Ignored. Whatever you send here is replaced with the `memberId` from the route before anything else happens, so a mismatch between the two is silently resolved in favour of the route and never reported as an error. |
| `typeKey` | string | Yes | The preference being stored. `Language` is the only key the endpoint supports — any other value fails with `The personalisation type {typeKey} is not currently supported.` if the key exists in the tenant's configuration, or `Personalisation Key: {typeKey} does not exist.` if it does not. Cannot be empty. |
| `value` | string | Yes | The preference itself. For `Language` this is a culture code checked, case-insensitively, against the tenant's list of allowed languages; a value that is not on the list is not rejected but replaced with `en-GB` and saved in its place. Cannot be empty. |
| `personalisationId` | integer (int32) | No | Ignored on create. The record's id is allocated for you and returned as `id` in the response; this field is only used by the update endpoint, where it identifies the record being changed. |

## Sample request

```bash title="cURL"
curl -X POST '{base_url}/api/members/{memberId}/personalisation' \
  -H 'Authorization: Bearer {accessToken}' \
  -H 'X-Use-SSO: true' \
  -H 'Content-Type: application/json' \
  -d '{
  "memberId": 12345,
  "typeKey": "string",
  "value": "string",
  "personalisationId": 12345
}'
```

## Response fields

| Field | Type | Description |
|-------|------|-------------|
| `id` | integer (int32) | The id of the personalisation record just created. Keep it: it is the `{personalisationId}` route value that `PUT {base_url}/api/members/{memberId}/personalisation/{personalisationId}` needs in order to change this preference later. |

## Sample response

```json title="201 Created"
{
  "id": 12345
}
```

## Errors

| Status | Meaning | When |
|--------|---------|------|
| `400` | Bad request | `typeKey` names a personalisation type that is not configured (`Personalisation Key: {typeKey} does not exist.`) or one the endpoint does not handle (`The personalisation type {typeKey} is not currently supported.` — anything other than `Language`); `typeKey` or `value` is missing; or `memberId` in the route is zero or negative. |
| `404` | Not found | No member exists with the `memberId` in the route: `The member does not exist.` |
| `409` | Conflict | The member already holds a record for this key: `The member already has a personalisation with type {typeKey}`. Use the update endpoint to change the existing value instead. |
| `422` | Unprocessable entity | The tenant has no allowed-languages configuration, so the value cannot be validated: `The configuration for allowed languages is not set.` This is a configuration fault on our side, not a fault in your request — retrying will not clear it. |
| `500` | Internal server error | An unexpected server-side failure while saving the record. The response has no body. |
