# client.projects.memberships

> client.projects.memberships — the projects.memberships operations.

`client.projects.memberships` — the `projects.memberships` operations.

On `AsyncKindgi` every method is the same, awaited.

## `client.projects.memberships.list()`

```python signature
list(
    project_id: str | UUID,
    /,
    *,
    limit: int | None = None,
    cursor: str | None = None,
    timeout: float | None = None,
) -> ProjectMembershipCollectionPage
```

List direct memberships of a project. `GET /v1/projects/{projectId}/memberships`

Cursor-paginated. Direct-grant memberships only — team-mediated grants are resolved through the FGA store per tenant. For the project's editors and admins (`write`): a viewer sees the project, not who else is in it, and reads their own roles through `GET /v1/identity/users/{userId}/grants`.

## `client.projects.memberships.add()`

```python signature
add(
    project_id: str | UUID,
    body: AddProjectMembershipBody | Mapping[str, Any] | None = None,
    /,
    *,
    idempotency_key: str | None = None,
    timeout: float | None = None,
    **fields: Any,
) -> AddProjectMembershipResult
```

Add a user directly to a project. `POST /v1/projects/{projectId}/memberships`

Names the person by exactly one of `userId` and `email` (matched as the runtime matches emails when it adds a person); someone who is not a person of this tenant, or was removed from it, is refused with 404 `identity-user-not-found`. Adding a role the member already holds answers 201 with the existing record; another role, 409 `membership-exists` naming the role they hold (`details.role`), which is kept: use PATCH to change it.

## `client.projects.memberships.update_role()`

```python signature
update_role(
    project_id: str | UUID,
    user_id: str | UUID,
    body: UpdateProjectMembershipBody | Mapping[str, Any] | None = None,
    /,
    *,
    idempotency_key: str | None = None,
    timeout: float | None = None,
    **fields: Any,
) -> None
```

Change an existing project member's role. `PATCH /v1/projects/{projectId}/memberships/{userId}`

## `client.projects.memberships.remove()`

```python signature
remove(
    project_id: str | UUID,
    user_id: str | UUID,
    /,
    *,
    idempotency_key: str | None = None,
    timeout: float | None = None,
) -> None
```

Remove a user from a project (idempotent). `DELETE /v1/projects/{projectId}/memberships/{userId}`
