---
title: "Set member role"
method: PATCH
path: "/member/{userId}"
tags: ["Members"]
---

# Set member role

`PATCH /member/{userId}`

## Request

- Base URL: `https://api.elaichi.ai`
- URL: `https://api.elaichi.ai/member/{userId}`
- Auth: HTTP bearer

Sets a member's role. **A member holds exactly one role per organization.** `role_ids` must contain exactly one id and REPLACES whatever they held; zero or two or more answers 400 `role_cardinality`. To combine two roles' permissions, author a custom role (`POST /role`) — a second assignment would create a privilege level no role names. Takes effect on the member's next request. Requires `member:manage`, and you may only assign a role whose permissions you hold yourself, so a member admin cannot promote anyone (including themselves) past their own level. A browser session must also pass a fresh step-up reauthentication in the app (without it the call answers `428 step_up_required`). An organization API token is not challenged.

## Path parameters

- `userId` string, required

## Headers

- `X-Organization-Id` string

## Request body

- object
  - `role_ids` string[], required: Exactly one role (`role_…`). It replaces the member's current role.

## Response `200`

OK

- Member: One organization membership, enriched with the global user profile.
  - `user_id` string: User id (`usr_…`). A membership has no id of its own.
  - `status` string: Only `active` members can act in the organization.
  - `via` string, nullable: How they joined — invite, verified domain, SCIM, and so on.
  - `joined_at` string, date-time
  - `roles` object[]: Roles held. Replace the whole set with `PATCH /member/{userId}`.
    - `id` string: Role id (`role_…`).
    - `name` string
    - `is_system` boolean
    - `seat_class` 'billable' | 'free_admin'
  - `teams` object[]
    - `id` string: Team id (`team_…`).
    - `name` string
  - `user` object, nullable: Global profile. Null when the profile row could not be resolved.
    - `id` string
    - `email` string, email
    - `name` string, nullable
    - `avatar_url` string, nullable

## Other responses

- `400`: Bad request
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not found
- `429`: Rate limited

---

[API](https://skmtc.dev/elaichi/apis/elaichi-api.md) · [All operations](https://skmtc.dev/elaichi/apis/elaichi-api/llms.txt) · [OpenAPI document](https://skmtc.dev/elaichi/apis/elaichi-api/revisions/b22cfb7b6d15?raw)
