# Comments

12 endpoints.

## List review comments for a composer group, or across a workspace

```http
GET https://orbitwrite.com/api/v1/comments
```

With `groupId`: that group's whole comment list, oldest first, plus the caller's mute and read state for it. A brand-new unsaved draft (no group row yet) returns an empty result. Without it: every comment in the workspace (`organizationId`), newest first and cursor-paged, filterable by `resolved`, `kind`, `suggestionStatus` and `suggestionType`; the mute and read state then cover the threads on the page, and `postMuted` is always false. The filters and `cursor` belong to the workspace listing and are refused alongside `groupId`.

**Authentication:** session cookie.

### Query parameters

- `groupId` (string, optional)
- `organizationId` (string, optional) — The workspace to list when `groupId` is omitted. Defaults to the session's active workspace.
- `limit` (integer, optional) — Workspace listing page size (default 50).
- `cursor` (string, optional) — Opaque cursor from a previous response's `nextCursor`. Omit for the first page.
- `resolved` (string, optional) — Only resolved rows, or only open ones. A decided suggestion counts as resolved. Omit for both.
- `kind` (string, optional)
- `suggestionStatus` (string | string[], optional) — A suggestion's decision state. Repeat for OR.
- `suggestionType` (string | string[], optional) — Which edit a suggestion tracks. Repeat for OR (e.g. `?suggestionType=insert&suggestionType=replace`).

### Responses

#### 200

Comments, with the caller's mute and read state for the group (or the page's threads).

- `ok` (boolean, required, one of `true`)
- `comments` (Comment[], required)
  - `id` (string, required)
  - `groupId` (string, required) — The composer group (post) the comment hangs off.
  - `parentId` (string | null, required)
  - `accountId` (string | null, required)
  - `threadPosition` (number | null, required)
  - `quote` (string | null, required)
  - `body` (string, required)
  - `attachments` (CommentAttachment[], required)
    - `url` (string, required)
    - `mimeType` (string, required)
  - `mentions` (CommentMention[], required)
    - `userId` (string, required)
    - `name` (string, required)
  - `reactions` (CommentReaction[], required)
    - `emoji` (string, required)
    - `count` (number, required)
    - `reactedByMe` (boolean, required)
  - `resolved` (boolean, required)
  - `createdAt` (number, required) — Epoch ms.
  - `author` (object, required)
    - `id` (string, required)
    - `name` (string, required)
    - `avatarUrl` (string | null, required)
  - `kind` (string, required, one of `comment`, `suggestion`) — "comment" (default) or "suggestion" — a tracked insert/delete made in suggestion mode.
  - `suggestionType` (string | null, required, one of `insert`, `delete`, `replace`, `null`)
  - `suggestionStatus` (string | null, required, one of `pending`, `accepted`, `rejected`, `null`)
- `postMuted` (boolean, required)
- `mutedThreadIds` (string[], required)
- `readState` (object, required) — threadId → lastReadAt (epoch ms) for the requesting user.
- `nextCursor` (string | null, required) — Workspace listing only: pass back as `cursor` for the next page; null on the last page. Always null for one group, which is returned whole.

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

## Create a comment

```http
POST https://orbitwrite.com/api/v1/comments
```

Adds a top-level review comment (or a tracked suggestion) to a composer group. Any member of the group's organization may comment; a suggestion also needs a plan that includes suggested edits (Pro and up). Retrying with the same `id` is idempotent.

**Authentication:** session cookie.

### Request body (`application/json`)

- `groupId` (string, required) — The composer group the comment belongs to.
- `id` (string, optional)
- `accountId` (string | null, optional)
- `threadPosition` (number | null, optional)
- `quote` (string | null, optional)
- `body` (string, optional)
- `attachments` (any[], optional)
- `mentions` (any[], optional)
- `kind` (string, optional, one of `comment`, `suggestion`)
- `suggestionType` (string, optional, one of `insert`, `delete`, `replace`)

### Responses

#### 200

The comment was created; `id` is the persisted id.

- `ok` (boolean, required, one of `true`)
- `id` (string, required)

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

#### 404

Group not found

- `error` (string, required)
- `issues` (any[], optional)

## Mute or unmute the whole post's comments

```http
PUT https://orbitwrite.com/api/v1/comments/post-mute
```

Sets the caller's post-level subscription: muted unsubscribes them from all comment activity on the group. Per-user — nobody else's notifications change.

**Authentication:** session cookie.

### Request body (`application/json`)

- `groupId` (string, required) — The composer group the comment belongs to.
- `muted` (boolean, required)

### Responses

#### 200

The operation was applied

- `ok` (boolean, required, one of `true`)

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

#### 404

Group not found

- `error` (string, required)
- `issues` (any[], optional)

## Mark all comment threads as read

```http
POST https://orbitwrite.com/api/v1/comments/read-all
```

Stamps the caller's read marker for every thread in the group at now.

**Authentication:** session cookie.

### Request body (`application/json`)

- `groupId` (string, required) — The composer group the comment belongs to.

### Responses

#### 200

The operation was applied

- `ok` (boolean, required, one of `true`)

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

#### 404

Group not found

- `error` (string, required)
- `issues` (any[], optional)

## Reply to a comment

```http
POST https://orbitwrite.com/api/v1/comments/{id}/replies
```

Adds a reply under a top-level comment. Replies can't nest further. Retrying with the same `id` is idempotent.

**Authentication:** session cookie.

### Path parameters

- `id` (string, required)

### Request body (`application/json`)

- `groupId` (string, required) — The composer group the comment belongs to.
- `id` (string, optional)
- `body` (string, optional)
- `attachments` (any[], optional)
- `mentions` (any[], optional)

### Responses

#### 200

The reply was created; `id` is the persisted id.

- `ok` (boolean, required, one of `true`)
- `id` (string, required)

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

#### 404

Group or parent comment not found

- `error` (string, required)
- `issues` (any[], optional)

## Edit a comment

```http
PATCH https://orbitwrite.com/api/v1/comments/{id}
```

Author-only: updates a comment's (or reply's) body, attachments and mentions. Suggestion quote-sync edits also carry `quote`.

**Authentication:** session cookie.

### Path parameters

- `id` (string, required)

### Request body (`application/json`)

- `groupId` (string, required) — The composer group the comment belongs to.
- `body` (string, optional)
- `attachments` (any[], optional)
- `mentions` (any[], optional)
- `quote` (string | null, optional)

### Responses

#### 200

The operation was applied

- `ok` (boolean, required, one of `true`)

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

#### 404

Group not found

- `error` (string, required)
- `issues` (any[], optional)

## Delete a comment

```http
DELETE https://orbitwrite.com/api/v1/comments/{id}
```

Removes a comment or reply. Authors delete their own; a caller with `comment:manageAny` (manager and up) may also remove someone else's. Deleting a top-level comment removes its whole thread.

**Authentication:** session cookie.

### Path parameters

- `id` (string, required)

### Query parameters

- `groupId` (string, required)

### Responses

#### 200

The operation was applied

- `ok` (boolean, required, one of `true`)

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

#### 404

Group not found

- `error` (string, required)
- `issues` (any[], optional)

## Resolve or reopen a comment thread

```http
PUT https://orbitwrite.com/api/v1/comments/{id}/resolved
```

Sets the thread's resolved state. Any member of the group's organization may resolve — not just the author.

**Authentication:** session cookie.

### Path parameters

- `id` (string, required)

### Request body (`application/json`)

- `groupId` (string, required) — The composer group the comment belongs to.
- `resolved` (boolean, required)

### Responses

#### 200

The operation was applied

- `ok` (boolean, required, one of `true`)

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

#### 404

Group not found

- `error` (string, required)
- `issues` (any[], optional)

## Add or remove an emoji reaction

```http
PUT https://orbitwrite.com/api/v1/comments/{id}/reaction
```

Sets the caller's reaction with one emoji on a comment or reply.

**Authentication:** session cookie.

### Path parameters

- `id` (string, required)

### Request body (`application/json`)

- `groupId` (string, required) — The composer group the comment belongs to.
- `emoji` (string, required)
- `reacted` (boolean, required) — Desired end state: true adds the caller's reaction, false removes it. Idempotent either way.

### Responses

#### 200

The operation was applied

- `ok` (boolean, required, one of `true`)

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

#### 404

Group or comment not found

- `error` (string, required)
- `issues` (any[], optional)

## Accept or reject a suggestion

```http
POST https://orbitwrite.com/api/v1/comments/{id}/decision
```

Decides a tracked suggestion, marking it resolved. The decision is terminal: retrying the same decision is idempotent, flipping it is a conflict.

**Authentication:** session cookie.

### Path parameters

- `id` (string, required)

### Request body (`application/json`)

- `groupId` (string, required) — The composer group the comment belongs to.
- `decision` (string, required, one of `accepted`, `rejected`)

### Responses

#### 200

The operation was applied

- `ok` (boolean, required, one of `true`)

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

#### 404

Group or suggestion not found

- `error` (string, required)
- `issues` (any[], optional)

#### 409

The suggestion was already decided the other way

- `error` (string, required)
- `issues` (any[], optional)

## Mute or unmute a comment thread

```http
PUT https://orbitwrite.com/api/v1/comments/{id}/mute
```

Sets the caller's mute state for one thread (a top-level comment): muted threads stop notifying them. Per-user — nobody else's notifications change.

**Authentication:** session cookie.

### Path parameters

- `id` (string, required)

### Request body (`application/json`)

- `groupId` (string, required) — The composer group the comment belongs to.
- `muted` (boolean, required)

### Responses

#### 200

The operation was applied

- `ok` (boolean, required, one of `true`)

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

#### 404

Group not found

- `error` (string, required)
- `issues` (any[], optional)

## Mark a comment thread as read

```http
PUT https://orbitwrite.com/api/v1/comments/{id}/read
```

Stamps the caller's read marker for one thread (a top-level comment) at now.

**Authentication:** session cookie.

### Path parameters

- `id` (string, required)

### Request body (`application/json`)

- `groupId` (string, required) — The composer group the comment belongs to.

### Responses

#### 200

The operation was applied

- `ok` (boolean, required, one of `true`)

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

#### 404

Group not found

- `error` (string, required)
- `issues` (any[], optional)
