# Members

> Decide who can open a document and with which role, and transfer ownership.

Members are the users who can open a document, each with a role. Your sharing screens decide who gets in; these endpoints tell Proof, which enforces the role in the editor and for each person's agents. People who aren't members can still open a document through its [link access](/reference/api/documents/#update-a-document). See [Documents and access](/concepts/documents-and-access/).

| Role | Can |
| --- | --- |
| `owner` | Everything an editor can, and seal the document. A document has one or more owners, and always at least one. |
| `editor` | Write, accept and reject suggestions, comment. Can turn on suggesting for themselves. |
| `suggester` | Propose changes as suggestions and comment. Every edit they make is a suggestion. |
| `viewer` | Read, and see comments. |

A person's agents never get more than the person's own role, and never ownership. When you lower someone's role, their agents' access drops with it.

## The member object

| Attribute | Type | Description |
| --- | --- | --- |
| `document` | string | The document's id. |
| `user` | string | The member's Proof id. |
| `name` | string | The user's current name. |
| `role` | string | `owner`, `editor`, `suggester` or `viewer`. |
| `added_at` | timestamp | When they became a member. |

```json
{
  "document": "doc_8Hq2Lm4R",
  "user": "usr_9Tb3Wc1X",
  "name": "Grace Hopper",
  "role": "suggester",
  "added_at": "2026-10-13T22:05:17Z"
}
```

## List members

`GET /v1/documents/{document_id}/members`

The document's members, owners first, then in the order they were added.

| Parameter | Type | Description |
| --- | --- | --- |
| `document_id` | string, path, required | The document's id. |
| `limit` | integer | 1 to 100. Default 50. |
| `after` | string | The `next` cursor from the previous page. |

<Tabs syncKey="lang">
<TabItem label="curl">

```bash
curl https://api.proof.exalto.ai/v1/documents/doc_8Hq2Lm4R/members \
  -H "Authorization: Bearer $PROOF_SECRET_KEY"
```

</TabItem>
<TabItem label="Node">

```ts
const page = await proof.members.list("doc_8Hq2Lm4R");
```

</TabItem>
</Tabs>

```json
{
  "data": [
    {
      "document": "doc_8Hq2Lm4R",
      "user": "usr_5Kq2Lm8R",
      "name": "Ada Lovelace",
      "role": "owner",
      "added_at": "2026-10-13T21:12:40Z"
    },
    {
      "document": "doc_8Hq2Lm4R",
      "user": "usr_9Tb3Wc1X",
      "name": "Grace Hopper",
      "role": "suggester",
      "added_at": "2026-10-13T22:05:17Z"
    }
  ],
  "next": null
}
```

## Add or change a member

`PUT /v1/documents/{document_id}/members/{user_id}`

Adds the user as a member with `role`, or changes their role if they're one already. The change reaches open editors at once: someone made a suggester mid-sentence carries on writing as suggestions.

Setting `role` to `owner` makes them an owner too; the others stay owners. To hand a document over, make the new person an owner, then lower the old owner's role or remove them. A member added again comes out of their own trash.

| Parameter | Type | Description |
| --- | --- | --- |
| `document_id` | string, path, required | The document's id. |
| `user_id` | string, path, required | The user's Proof id. The user must exist. |
| `role` | string, required | `owner`, `editor`, `suggester` or `viewer`. |

<Tabs syncKey="lang">
<TabItem label="curl">

```bash
curl https://api.proof.exalto.ai/v1/documents/doc_8Hq2Lm4R/members/usr_9Tb3Wc1X \
  -X PUT \
  -H "Authorization: Bearer $PROOF_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"role": "suggester"}'
```

</TabItem>
<TabItem label="Node">

```ts
const member = await proof.members.put("doc_8Hq2Lm4R", "usr_9Tb3Wc1X", { role: "suggester" });
```

</TabItem>
</Tabs>

Returns the [member](#the-member-object): `201` when they were added, `200` when their role changed.

```json
{
  "document": "doc_8Hq2Lm4R",
  "user": "usr_9Tb3Wc1X",
  "name": "Grace Hopper",
  "role": "suggester",
  "added_at": "2026-10-13T22:05:17Z"
}
```

| Error | When |
| --- | --- |
| `404 user_not_found` | The user doesn't exist. Create them with [`PUT /v1/users/external/{external_id}`](/reference/api/users/#create-or-update-a-user) first. |
| `409 last_owner` | You tried to give the only owner a lower role. Make someone else an owner first. |
| `409 document_trashed` | The document is in the trash. |

## Remove a member

`DELETE /v1/documents/{document_id}/members/{user_id}`

Takes away a member's access. Their open editors close, and their agents lose the document. What they wrote stays credited to them.

People can still reach the document through link access afterwards if its `link_access` lets them in and you start a session for them with `via: "link"`.

| Parameter | Type | Description |
| --- | --- | --- |
| `document_id` | string, path, required | The document's id. |
| `user_id` | string, path, required | The user's Proof id. |

<Tabs syncKey="lang">
<TabItem label="curl">

```bash
curl https://api.proof.exalto.ai/v1/documents/doc_8Hq2Lm4R/members/usr_9Tb3Wc1X \
  -X DELETE \
  -H "Authorization: Bearer $PROOF_SECRET_KEY"
```

</TabItem>
<TabItem label="Node">

```ts
await proof.members.delete("doc_8Hq2Lm4R", "usr_9Tb3Wc1X");
```

</TabItem>
</Tabs>

```json
{
  "document": "doc_8Hq2Lm4R",
  "user": "usr_9Tb3Wc1X",
  "removed": true
}
```

| Error | When |
| --- | --- |
| `404 member_not_found` | The user isn't a member. |
| `409 last_owner` | The user is the only owner. Make someone else an owner first, or [delete the document](/reference/api/documents/#delete-a-document). |