---
title: "Change a member's role."
method: PATCH
path: "/story-projects/{projectId}/members/{userId}"
tags: ["Projects"]
---

# Change a member's role.

`PATCH /story-projects/{projectId}/members/{userId}`

## Request

- Base URL: `https://docs.sleeperhit.studio/api/v1`
- URL: `https://docs.sleeperhit.studio/api/v1/story-projects/{projectId}/members/{userId}`
- Auth: HTTP bearer

Make the member an `editor` or a `viewer`. The owner or an admin (403 `project_owner_only` for a member). 404 `project_member_not_found` for an account that is not a member. Audited. Scope: `story:write`. Free.

## Request body

- UpdateProjectMemberRequest
  - `role` 'editor' | 'viewer', required

## Response `200`

The members now, and the one changed.

- ProjectMemberChange
  - `projectId` string, required
  - `yourUserId` string, required: The caller's own user id.
  - `yourRole` 'owner' | 'editor' | 'viewer' | 'null', nullable, required: The caller's own role; null for an admin who is neither the owner nor a member.
  - `canManage` boolean, required: Whether the caller may add, change or remove members: the owner, or an admin.
  - `members` ProjectMember[], required: The owner first, then the members, oldest first.
    - `userId` string, required
    - `email` string, required
    - `name` string, nullable, required
    - `role` 'owner' | 'editor' | 'viewer', required: `owner` (the project's own account), `editor` or `viewer`.
    - `addedAt` string, date-time, nullable, required: When the account was added; null for the owner.
  - `changed` boolean, required: False when nothing changed: the member already had that role, or was not a member.
  - `member` ProjectMember, required
    - `userId` string, required
    - `email` string, required
    - `name` string, nullable, required
    - `role` 'owner' | 'editor' | 'viewer', required: `owner` (the project's own account), `editor` or `viewer`.
    - `addedAt` string, date-time, nullable, required: When the account was added; null for the owner.

## Other responses

- `401`: Missing, malformed, revoked, or expired API key.
- `403`: API key is valid but lacks the scope, is blocked by IP allowlist, or the account is disabled.
- `429`: Rate limit for this API key + IP + route family was exceeded.
- `500`: The API failed unexpectedly. Safe to retry with the same Idempotency-Key.

---

[API](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api.md) · [All operations](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/llms.txt) · [OpenAPI document](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/revisions/4534f5d25540?raw)
