# POS Access Management

Manage POS user access: roles, groups, and individual users. Roles define permission sets that control what actions a POS operator can perform. Groups organize POS devices and users together. Users represent individual POS operators with PIN-based authentication.

#### Key Concepts

Role

A named permission set (e.g. Manager, Cashier) that defines which POS screens and actions a user can access.

Group

A logical grouping of POS devices and users. Each restaurant can have multiple groups. One group is marked as default.

User

An individual POS operator identified by name and a 4- or 8-character PIN code. Assigned to a role that determines their permissions.

### Roles

### `GET /restaurants/{restaurantId}/pos_access/roles` - List all POS roles

Retrieve all POS access roles defined for a restaurant. Each role contains a name, a key, and a list of permissions.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| restaurantId | integer | Yes | The unique identifier of the restaurant. |

#### Response

```json
{
  "status": 200,
  "code": "pos_access_roles_found",
  "message": "POS access groups have been found",
  "data": [
    {
      "posRoleId": 101,
      "restaurantId": 4200,
      "key": "manager",
      "name": "Manager",
      "permissions": [
        "ACCESS_NEW_ORDER_SCREEN",
        "ACCESS_TICKET_SCREEN",
        "ACCESS_RAZ_SCREEN",
        "CANCEL_ORDER",
        "APPLY_DISCOUNT"
      ]
    },
    {
      "posRoleId": 102,
      "restaurantId": 4200,
      "key": "cashier",
      "name": "Cashier",
      "permissions": [
        "ACCESS_NEW_ORDER_SCREEN",
        "ACCESS_TICKET_SCREEN"
      ]
    }
  ]
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "pos\_access\_roles\_found" | Machine-readable application code for the result. |
| message | string | "POS access groups have been found" | Human-readable result message. Do not use this value for program logic. |
| data | array | \[…\] | Endpoint-specific response payload. |
| data\[\] | object | {…} | Endpoint-specific response payload. |
| data\[\].posRoleId | integer | 101 | Identifier of the associated pos role. |
| data\[\].restaurantId | integer | 4200 | Identifier of the restaurant. |
| data\[\].key | string | "manager" | The key value. |
| data\[\].name | string | "Manager" | The name value. |
| data\[\].permissions | array | \[…\] | List of permissions entries. |
| data\[\].permissions\[\] | string | "ACCESS\_NEW\_ORDER\_SCREEN" | The permissions value. |

### `GET /restaurants/{restaurantId}/pos_access/roles/permissions` - List all available permissions

Returns the full list of assignable POS permissions. Use this to build a permission editor UI.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| restaurantId | integer | Yes | The unique identifier of the restaurant. |

#### Response

```json
{
  "status": 200,
  "code": "pos_access_roles_found",
  "message": "POS access groups have been found",
  "data": [
    "ACCESS_CATALOG_SCREEN",
    "ACCESS_CUSTOMISATION_SCREEN",
    "ACCESS_E_WALLET_SCREEN",
    "ACCESS_MANAGE_CASH_FLOAT_SCREEN",
    "ACCESS_MANAGE_DISCOUNT_SCREEN",
    "ACCESS_MANAGE_RUNNER_SCREEN",
    "ACCESS_MANAGE_TABLES_SCREEN",
    "ACCESS_NEW_ORDER_SCREEN",
    "ACCESS_ORDERS_FOLLOW_UP_SCREEN",
    "ACCESS_PARAMETER_SCREEN",
    "ACCESS_PRINTER_SCREEN",
    "ACCESS_RAZ_SCREEN",
    "ACCESS_TICKET_SCREEN",
    "APPLY_DISCOUNT",
    "CANCEL_ORDER",
    "CANCEL_VALIDATED_ORDER_ITEM",
    "CREATE_GROUP",
    "CREATE_PRODUCT",
    "DELETE_DEFAULT_PRINTER",
    "DISCONNECT",
    "ENTER_DISCOUNT_WHEN_PLACING_AN_ORDER",
    "EXPORT_ARCHIVE",
    "GENERATE_ARCHIVE",
    "JUSTIFY_ORDERS",
    "LINK_A_BADGE",
    "MODIFY_FEATURE_OPTIONS",
    "MODIFY_GROUP_FROM_GRID",
    "MODIFY_ORDER_ITEM_PRICE",
    "MODIFY_PASSWORD",
    "MODIFY_PRODUCT_FROM_GRID",
    "MODIFY_SKU_BILLING_CODE_PURCHASE_PRICE",
    "MODIFY_PRODUCT_PRICE",
    "MODIFY_PRODUCT_OTHER_INFO",
    "MODIFY_TICKET",
    "MODIFY_TICKET_GROUPS",
    "MODIFY_TICKET_ORDER_PLACES",
    "MODIFY_TICKET_ORDER_STATUS",
    "MODIFY_TICKET_QUANTITY",
    "MODIFY_VALIDATED_ORDER_ITEM",
    "OFFER_PRODUCT_FOR_FREE",
    "OPEN_CASH_DRAWER",
    "PRINT_VALID_TICKET",
    "REFUND_CLIENT",
    "REMOVE_PRODUCT_FROM_CATALOG",
    "REOPEN_ORDER",
    "SEARCH_CLIENT",
    "SHOW_APPLY_PRICING_RULE_BUTTON",
    "SYNC_ARCHIVE",
    "VIEW_AUDIT_TRAIL",
    "VIEW_FEATURE_OPTIONS",
    "VIEW_ORDER_AUDIT",
    "VIEW_REVENUE_IN_FOLLOW_UP",
    "VIEW_TICKET_AUDIT",
    "VIEW_TICKET_TEMPLATE",
    "ACCESS_CUSTOMERS_SCREEN",
    "MODIFY_TICKET_PRINTER",
    "FORCE_ORDER_SHIFT",
    "VALIDATE_EPT_PAYMENT_OPERATIONS",
    "MODIFY_FUNCTION_FROM_GRID"
  ]
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "pos\_access\_roles\_found" | Machine-readable application code for the result. |
| message | string | "POS access groups have been found" | Human-readable result message. Do not use this value for program logic. |
| data | array | \[…\] | Endpoint-specific response payload. |
| data\[\] | string | "ACCESS\_CATALOG\_SCREEN" | Endpoint-specific response payload. |

### `GET /restaurants/{restaurantId}/pos_access/roles/{roleId}` - Get a single POS role

Retrieve a specific POS role by its ID, including its permission list.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| restaurantId | integer | Yes | The unique identifier of the restaurant. |
| roleId | integer | Yes | The unique identifier of the POS role. |

#### Response

```json
{
  "status": 200,
  "code": "pos_access_role_found",
  "message": "POS access group has been found",
  "data": {
    "posRoleId": 101,
    "restaurantId": 4200,
    "key": "manager",
    "name": "Manager",
    "permissions": [
      "ACCESS_NEW_ORDER_SCREEN",
      "ACCESS_TICKET_SCREEN",
      "ACCESS_RAZ_SCREEN",
      "CANCEL_ORDER",
      "APPLY_DISCOUNT"
    ]
  }
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "pos\_access\_role\_found" | Machine-readable application code for the result. |
| message | string | "POS access group has been found" | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.posRoleId | integer | 101 | Identifier of the associated pos role. |
| data.restaurantId | integer | 4200 | Identifier of the restaurant. |
| data.key | string | "manager" | The key value. |
| data.name | string | "Manager" | The name value. |
| data.permissions | array | \[…\] | List of permissions entries. |
| data.permissions\[\] | string | "ACCESS\_NEW\_ORDER\_SCREEN" | The permissions value. |

### `PATCH /restaurants/{restaurantId}/pos_access/roles/{roleId}` - Update a POS role's permissions

Replace the permission list of a POS role. Send the full desired list of permissions.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| restaurantId | integer | Yes | The unique identifier of the restaurant. |
| roleId | integer | Yes | The unique identifier of the POS role. |

#### Request Body

```json
{
  "permissions": [
    "ACCESS_NEW_ORDER_SCREEN",
    "ACCESS_TICKET_SCREEN",
    "CANCEL_ORDER"
  ]
}
```

##### Request Body Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| permissions | array | \[…\] | List of permissions entries. |
| permissions\[\] | string | "ACCESS\_NEW\_ORDER\_SCREEN" | The permissions value. |

#### Response

```json
{
  "status": 200,
  "code": "pos_access_role_updated",
  "message": "POS access role has been updated",
  "data": {
    "posRoleId": 101,
    "restaurantId": 4200,
    "key": "manager",
    "name": "Manager",
    "permissions": [
      "ACCESS_NEW_ORDER_SCREEN",
      "ACCESS_TICKET_SCREEN",
      "CANCEL_ORDER"
    ]
  }
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "pos\_access\_role\_updated" | Machine-readable application code for the result. |
| message | string | "POS access role has been updated" | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.posRoleId | integer | 101 | Identifier of the associated pos role. |
| data.restaurantId | integer | 4200 | Identifier of the restaurant. |
| data.key | string | "manager" | The key value. |
| data.name | string | "Manager" | The name value. |
| data.permissions | array | \[…\] | List of permissions entries. |
| data.permissions\[\] | string | "ACCESS\_NEW\_ORDER\_SCREEN" | The permissions value. |

### Groups

### `GET /restaurants/{restaurantId}/pos_access/groups` - List all POS access groups

Retrieve all POS access groups for a restaurant. Each group includes its associated POS devices and users.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| restaurantId | integer | Yes | The unique identifier of the restaurant. |

#### Response

```json
{
  "status": 200,
  "code": "pos_access_groups_found",
  "message": "POS access roles have been found",
  "data": [
    {
      "posAccessGroupId": 10,
      "restaurantId": 4200,
      "name": "Main Floor",
      "isDefault": true,
      "posDevices": [
        {
          "posDeviceId": 501
        },
        {
          "posDeviceId": 502
        }
      ],
      "posUsers": [
        {
          "posUserId": 1,
          "name": "Alice",
          "posRoleId": 101
        },
        {
          "posUserId": 2,
          "name": "Bob",
          "posRoleId": 102
        }
      ]
    }
  ]
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "pos\_access\_groups\_found" | Machine-readable application code for the result. |
| message | string | "POS access roles have been found" | Human-readable result message. Do not use this value for program logic. |
| data | array | \[…\] | Endpoint-specific response payload. |
| data\[\] | object | {…} | Endpoint-specific response payload. |
| data\[\].posAccessGroupId | integer | 10 | Identifier of the associated pos access group. |
| data\[\].restaurantId | integer | 4200 | Identifier of the restaurant. |
| data\[\].name | string | "Main Floor" | The name value. |
| data\[\].isDefault | boolean | true | Whether default is enabled or applies. |
| data\[\].posDevices | array | \[…\] | List of pos devices entries. |
| data\[\].posDevices\[\] | object | {…} | Object containing pos devices fields. |
| data\[\].posDevices\[\].posDeviceId | integer | 501 | Identifier of the associated pos device. |
| data\[\].posUsers | array | \[…\] | List of pos users entries. |
| data\[\].posUsers\[\] | object | {…} | Object containing pos users fields. |
| data\[\].posUsers\[\].posUserId | integer | 1 | Identifier of the associated pos user. |
| data\[\].posUsers\[\].name | string | "Alice" | The name value. |
| data\[\].posUsers\[\].posRoleId | integer | 101 | Identifier of the associated pos role. |

### `POST /restaurants/{restaurantId}/pos_access/groups` - Create a POS access group

Create a new POS access group for a restaurant. Optionally associate POS devices and users at creation time.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| restaurantId | integer | Yes | The unique identifier of the restaurant. |

#### Request Body

```json
{
  "name": "Terrace",
  "posDeviceIds": [
    503
  ],
  "posUserIds": [
    3,
    4
  ]
}
```

##### Request Body Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| name | string | "Terrace" | The name value. |
| posDeviceIds | array | \[…\] | List of pos device ids entries. |
| posDeviceIds\[\] | integer | 503 | The pos device ids value. |
| posUserIds | array | \[…\] | List of pos user ids entries. |
| posUserIds\[\] | integer | 3 | The pos user ids value. |

#### Response

```json
{
  "status": 200,
  "code": "pos_access_group_created",
  "message": "POS access group has been created",
  "data": {
    "posAccessGroupId": 11,
    "restaurantId": 4200,
    "name": "Terrace",
    "isDefault": false,
    "posDevices": [
      {
        "posDeviceId": 503
      }
    ],
    "posUsers": [
      {
        "posUserId": 3,
        "name": "Carol",
        "posRoleId": 101
      },
      {
        "posUserId": 4,
        "name": "Dave",
        "posRoleId": 102
      }
    ]
  }
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "pos\_access\_group\_created" | Machine-readable application code for the result. |
| message | string | "POS access group has been created" | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.posAccessGroupId | integer | 11 | Identifier of the associated pos access group. |
| data.restaurantId | integer | 4200 | Identifier of the restaurant. |
| data.name | string | "Terrace" | The name value. |
| data.isDefault | boolean | false | Whether default is enabled or applies. |
| data.posDevices | array | \[…\] | List of pos devices entries. |
| data.posDevices\[\] | object | {…} | Object containing pos devices fields. |
| data.posDevices\[\].posDeviceId | integer | 503 | Identifier of the associated pos device. |
| data.posUsers | array | \[…\] | List of pos users entries. |
| data.posUsers\[\] | object | {…} | Object containing pos users fields. |
| data.posUsers\[\].posUserId | integer | 3 | Identifier of the associated pos user. |
| data.posUsers\[\].name | string | "Carol" | The name value. |
| data.posUsers\[\].posRoleId | integer | 101 | Identifier of the associated pos role. |

### `GET /restaurants/{restaurantId}/pos_access/groups/{groupId}` - Get a single POS access group

Retrieve a specific POS access group by its ID, including associated devices and users.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| restaurantId | integer | Yes | The unique identifier of the restaurant. |
| groupId | integer | Yes | The unique identifier of the POS access group. |

#### Response

```json
{
  "status": 200,
  "code": "pos_access_group_found",
  "message": "POS access group has been found",
  "data": {
    "posAccessGroupId": 10,
    "restaurantId": 4200,
    "name": "Main Floor",
    "isDefault": true,
    "posDevices": [
      {
        "posDeviceId": 501
      },
      {
        "posDeviceId": 502
      }
    ],
    "posUsers": [
      {
        "posUserId": 1,
        "name": "Alice",
        "posRoleId": 101
      },
      {
        "posUserId": 2,
        "name": "Bob",
        "posRoleId": 102
      }
    ]
  }
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "pos\_access\_group\_found" | Machine-readable application code for the result. |
| message | string | "POS access group has been found" | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.posAccessGroupId | integer | 10 | Identifier of the associated pos access group. |
| data.restaurantId | integer | 4200 | Identifier of the restaurant. |
| data.name | string | "Main Floor" | The name value. |
| data.isDefault | boolean | true | Whether default is enabled or applies. |
| data.posDevices | array | \[…\] | List of pos devices entries. |
| data.posDevices\[\] | object | {…} | Object containing pos devices fields. |
| data.posDevices\[\].posDeviceId | integer | 501 | Identifier of the associated pos device. |
| data.posUsers | array | \[…\] | List of pos users entries. |
| data.posUsers\[\] | object | {…} | Object containing pos users fields. |
| data.posUsers\[\].posUserId | integer | 1 | Identifier of the associated pos user. |
| data.posUsers\[\].name | string | "Alice" | The name value. |
| data.posUsers\[\].posRoleId | integer | 101 | Identifier of the associated pos role. |

### `PATCH /restaurants/{restaurantId}/pos_access/groups/{groupId}` - Update a POS access group

Update the name and member assignments of a POS access group. Both posDeviceIds and posUserIds are required and will fully replace the current associations.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| restaurantId | integer | Yes | The unique identifier of the restaurant. |
| groupId | integer | Yes | The unique identifier of the POS access group. |

#### Request Body

```json
{
  "name": "Main Floor (Updated)",
  "posDeviceIds": [
    501,
    502,
    504
  ],
  "posUserIds": [
    1,
    2,
    5
  ]
}
```

##### Request Body Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| name | string | "Main Floor (Updated)" | The name value. |
| posDeviceIds | array | \[…\] | List of pos device ids entries. |
| posDeviceIds\[\] | integer | 501 | The pos device ids value. |
| posUserIds | array | \[…\] | List of pos user ids entries. |
| posUserIds\[\] | integer | 1 | The pos user ids value. |

#### Response

```json
{
  "status": 200,
  "code": "pos_access_group_updated",
  "message": "POS access group has been updated",
  "data": {
    "posAccessGroupId": 10,
    "restaurantId": 4200,
    "name": "Main Floor (Updated)",
    "isDefault": true
  }
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "pos\_access\_group\_updated" | Machine-readable application code for the result. |
| message | string | "POS access group has been updated" | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.posAccessGroupId | integer | 10 | Identifier of the associated pos access group. |
| data.restaurantId | integer | 4200 | Identifier of the restaurant. |
| data.name | string | "Main Floor (Updated)" | The name value. |
| data.isDefault | boolean | true | Whether default is enabled or applies. |

### `DELETE /restaurants/{restaurantId}/pos_access/groups/{groupId}` - Delete a POS access group

Delete a POS access group. The default group cannot be deleted.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| restaurantId | integer | Yes | The unique identifier of the restaurant. |
| groupId | integer | Yes | The unique identifier of the POS access group. |

#### Response

```json
{
  "status": 200,
  "code": "pos_access_group_deleted",
  "message": "POS access group has been deleted",
  "data": {}
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "pos\_access\_group\_deleted" | Machine-readable application code for the result. |
| message | string | "POS access group has been deleted" | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |

### Users

### `GET /restaurants/{restaurantId}/pos_access/users` - List all POS users

Retrieve all POS users for a restaurant. Each user includes their name, how they identify on the till, their role assignment, and associated role details.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| restaurantId | integer | Yes | The unique identifier of the restaurant. |

#### Response

```json
{
  "status": 200,
  "code": "pos_access_users_found",
  "message": "POS access users have been found",
  "data": [
    {
      "posUserId": 1,
      "restaurantId": 4200,
      "name": "Alice",
      "authenticationMethod": "PIN_CODE",
      "pinCode": "1234",
      "physicalKeyValue": null,
      "posRoleId": 101,
      "posRole": {
        "posRoleId": 101,
        "key": "manager",
        "name": "Manager"
      }
    },
    {
      "posUserId": 2,
      "restaurantId": 4200,
      "name": "Bob",
      "authenticationMethod": "PHYSICAL_KEY",
      "pinCode": null,
      "physicalKeyValue": "K-123",
      "posRoleId": 102,
      "posRole": {
        "posRoleId": 102,
        "key": "cashier",
        "name": "Cashier"
      }
    }
  ]
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "pos\_access\_users\_found" | Machine-readable application code for the result. |
| message | string | "POS access users have been found" | Human-readable result message. Do not use this value for program logic. |
| data | array | \[…\] | Endpoint-specific response payload. |
| data\[\] | object | {…} | Endpoint-specific response payload. |
| data\[\].posUserId | integer | 1 | Identifier of the associated pos user. |
| data\[\].restaurantId | integer | 4200 | Identifier of the restaurant. |
| data\[\].name | string | "Alice" | The name value. |
| data\[\].authenticationMethod | string | "PIN\_CODE" | The authentication method value. |
| data\[\].pinCode | string | "1234" | The pin code value. |
| data\[\].physicalKeyValue | null | null | The physical key value value. |
| data\[\].posRoleId | integer | 101 | Identifier of the associated pos role. |
| data\[\].posRole | object | {…} | Object containing pos role fields. |
| data\[\].posRole.posRoleId | integer | 101 | Identifier of the associated pos role. |
| data\[\].posRole.key | string | "manager" | The key value. |
| data\[\].posRole.name | string | "Manager" | The name value. |
| authenticationMethod | string | Not provided | How the operator identifies on the till: \`PIN\_CODE\` or \`PHYSICAL\_KEY\`. |
| pinCode | string \| null | Not provided | The PIN code, in clear text. Null when the operator identifies with a physical key. |
| physicalKeyValue | string \| null | Not provided | The physical key value, in clear text. Null when the operator identifies with a PIN code. |

### `POST /restaurants/{restaurantId}/pos_access/users` - Create a POS user

Create a new POS user for a restaurant. The operator identifies on the till with either a PIN code or a physical key, never both, so exactly one of \`pinCode\` and \`physicalKeyValue\` must be supplied. A profile with no secret at all is rejected with \`pos\_user\_authentication\_secret\_required\`.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| restaurantId | integer | Yes | The unique identifier of the restaurant. |

#### Request Body

```json
{
  "name": "Carol",
  "authenticationMethod": "PHYSICAL_KEY",
  "physicalKeyValue": "K-456",
  "posRoleId": 102
}
```

##### Request Body Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Required | Example | Description |
| --- | --- | --- | --- | --- |
| name | string | Yes | "Carol" | Operator name, 1 to 64 characters. |
| authenticationMethod | string | Not specified | "PHYSICAL\_KEY" | \`PIN\_CODE\` or \`PHYSICAL\_KEY\`. Defaults to \`PIN\_CODE\` when omitted. |
| physicalKeyValue | string | Not specified | "K-456" | Required when the method is \`PHYSICAL\_KEY\`. Up to 255 characters, unique among the profiles of the restaurant once normalised; a duplicate is rejected with \`pos\_user\_physical\_key\_value\_already\_used\`. Normalisation keeps what precedes the first line ending and trims the surrounding whitespace; case and inner spaces are significant. |
| posRoleId | integer | Yes | 102 | The POS role granted to the operator. |
| pinCode | string | Not specified | Not provided | Required when the method is \`PIN\_CODE\`. Exactly 4 or 8 characters. Ignored, and erased, when the method is \`PHYSICAL\_KEY\`. |

#### Response

```json
{
  "status": 200,
  "code": "pos_access_user_created",
  "message": "POS access user has been created",
  "data": {
    "posUserId": 3,
    "restaurantId": 4200,
    "name": "Carol",
    "authenticationMethod": "PHYSICAL_KEY",
    "pinCode": null,
    "physicalKeyValue": "K-456",
    "posRoleId": 102
  }
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "pos\_access\_user\_created" | Machine-readable application code for the result. |
| message | string | "POS access user has been created" | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.posUserId | integer | 3 | Identifier of the associated pos user. |
| data.restaurantId | integer | 4200 | Identifier of the restaurant. |
| data.name | string | "Carol" | The name value. |
| data.authenticationMethod | string | "PHYSICAL\_KEY" | The authentication method value. |
| data.pinCode | null | null | The pin code value. |
| data.physicalKeyValue | string | "K-456" | The physical key value value. |
| data.posRoleId | integer | 102 | Identifier of the associated pos role. |

### `GET /restaurants/{restaurantId}/pos_access/users/{userId}` - Get a single POS user

Retrieve a specific POS user by their ID.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| restaurantId | integer | Yes | The unique identifier of the restaurant. |
| userId | integer | Yes | The unique identifier of the POS user. |

#### Response

```json
{
  "status": 200,
  "code": "pos_access_user_found",
  "message": "POS access user has been found",
  "data": {
    "posUserId": 1,
    "restaurantId": 4200,
    "name": "Alice",
    "authenticationMethod": "PIN_CODE",
    "pinCode": "1234",
    "physicalKeyValue": null,
    "posRoleId": 101,
    "posRole": {
      "posRoleId": 101,
      "key": "manager",
      "name": "Manager"
    }
  }
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "pos\_access\_user\_found" | Machine-readable application code for the result. |
| message | string | "POS access user has been found" | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |
| data.posUserId | integer | 1 | Identifier of the associated pos user. |
| data.restaurantId | integer | 4200 | Identifier of the restaurant. |
| data.name | string | "Alice" | The name value. |
| data.authenticationMethod | string | "PIN\_CODE" | The authentication method value. |
| data.pinCode | string | "1234" | The pin code value. |
| data.physicalKeyValue | null | null | The physical key value value. |
| data.posRoleId | integer | 101 | Identifier of the associated pos role. |
| data.posRole | object | {…} | Object containing pos role fields. |
| data.posRole.posRoleId | integer | 101 | Identifier of the associated pos role. |
| data.posRole.key | string | "manager" | The key value. |
| data.posRole.name | string | "Manager" | The name value. |

### `PATCH /restaurants/{restaurantId}/pos_access/users/{userId}` - Update a POS user

Update a POS user's name, identification method, secret, or role assignment. All fields are optional, and a field left out keeps its stored value. Changing the identification method rewrites the secret rather than keeping both: it must be supplied in the same request, and the secret of the abandoned method is erased, which also frees a physical key value for another profile of the restaurant. The response carries no \`data\`; read the user back if you need the stored state.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| restaurantId | integer | Yes | The unique identifier of the restaurant. |
| userId | integer | Yes | The unique identifier of the POS user. |

#### Request Body

```json
{
  "name": "Alice M.",
  "authenticationMethod": "PHYSICAL_KEY",
  "physicalKeyValue": "K-789",
  "posRoleId": 101
}
```

##### Request Body Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| name | string | "Alice M." | Operator name, 1 to 64 characters. |
| authenticationMethod | string | "PHYSICAL\_KEY" | \`PIN\_CODE\` or \`PHYSICAL\_KEY\`. Omit to keep the current method. |
| physicalKeyValue | string | "K-789" | Required when switching to \`PHYSICAL\_KEY\`, otherwise the request is rejected with \`pos\_user\_physical\_key\_value\_required\`. Same uniqueness and normalisation rules as on creation. |
| posRoleId | integer | 101 | The POS role granted to the operator. |
| pinCode | string | Not provided | Exactly 4 or 8 characters. Required when switching to \`PIN\_CODE\`, since the previous code was erased when the key was set. Otherwise the request is rejected with \`pos\_user\_pin\_code\_required\`. |

#### Response

```json
{
  "status": 200,
  "code": "pos_access_user_updated",
  "message": "POS access user has been updated"
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "pos\_access\_user\_updated" | Machine-readable application code for the result. |
| message | string | "POS access user has been updated" | Human-readable result message. Do not use this value for program logic. |

### `DELETE /restaurants/{restaurantId}/pos_access/users/{userId}` - Delete a POS user

Delete a POS user from the restaurant.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| restaurantId | integer | Yes | The unique identifier of the restaurant. |
| userId | integer | Yes | The unique identifier of the POS user. |

#### Response

```json
{
  "status": 200,
  "code": "pos_access_user_deleted",
  "message": "POS access user has been deleted",
  "data": {}
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "pos\_access\_user\_deleted" | Machine-readable application code for the result. |
| message | string | "POS access user has been deleted" | Human-readable result message. Do not use this value for program logic. |
| data | object | {…} | Endpoint-specific response payload. |

### Publish POS Access

### `POST /restaurants/{restaurantId}/pos_access/publish` - Publish POS Access to a Device

Notifies the selected POS device to refresh its access roles, groups, and users. The caller must have access to the restaurant.

#### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| restaurantId | integer | Yes | Restaurant whose POS access configuration is published. |

#### Request Body

```json
{
  "posDeviceId": 501
}
```

##### Request Body Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Required | Example | Description |
| --- | --- | --- | --- | --- |
| posDeviceId | integer | Yes | 501 | Target POS device that receives the access-configuration update. |

#### Response

```json
{
  "status": 200,
  "code": "pos_access_published",
  "message": "POS access has been published to the selected POS device."
}
```

##### Response Properties

Every field in the example is listed below. Explicit requiredness is shown when the endpoint contract defines it.

| Property | Type | Example | Description |
| --- | --- | --- | --- |
| status | integer | 200 | HTTP status code returned by the API. |
| code | string | "pos\_access\_published" | Machine-readable application code for the result. |
| message | string | "POS access has been published to the selected POS device." | Human-readable result message. Do not use this value for program logic. |
