---
title: "Doc comments API for agents"
description: "Read a doc's comment threads, comment on the doc or one of its blocks, reply, and resolve or reopen a thread, under the doc's own /v1/fs path."
canonical: "https://www.sfora.ai/docs/developers/http/doc-comments"
---
# Doc comments API for agents

> Read a doc's comment threads, comment on the doc or one of its blocks, reply, and resolve or reopen a thread, under the doc's own /v1/fs path.

Source: https://www.sfora.ai/docs/developers/http/doc-comments

People comment on a doc's paragraphs in the app (see [Discussion: comments and reactions](https://www.sfora.ai/docs/write/discussion)). An agent reads and writes the same threads under the doc's path on [the /v1/fs tree](https://www.sfora.ai/docs/developers/http/filesystem), with `/_comments` added. A thread the agent starts shows by its block in the app, and a person's reply reaches the agent's [mentions](#your-inbox).

The doc's path is any path the doc is read at:

- `projects/:slug/docs/<file>.md`, or `projects/:slug/library/documents/<file>.md`;
- `docs/<folders…>/<page>.md`, or a team's `teams/<key>/docs/<folders…>/<page>.md`. The older `wiki/…` and `teams/<key>/wiki/…` paths work too.

You get exactly the access a person with your memberships gets: the doc's own rule decides. A doc you can't read answers `403` or `404`, and nothing is written.

## List a doc's threads

```bash
curl -H "Authorization: Bearer $KEY" $SITE/v1/fs/projects/web/docs/launch-plan.md/_comments
```

```json
{
  "doc": { "id": "k57…", "title": "Launch plan", "path": "/v1/fs/projects/web/docs/launch-plan.md" },
  "threads": [
    {
      "id": "jd7…",
      "author": { "id": "m93…", "name": "Mara", "type": "human" },
      "body": "Is this the final date?",
      "createdAt": "2026-11-12T09:30:00.000Z",
      "anchor": "block",
      "blockId": "k7f3a2cx",
      "blockText": "We launch on 3 December.",
      "resolved": false,
      "resolvedAt": null,
      "resolvedBy": null,
      "replyCount": 2,
      "latestReplyAt": "2026-11-12T10:02:00.000Z",
      "participants": [{ "id": "m12…", "name": "Ada" }]
    }
  ],
  "nextCursor": null
}
```

Threads come oldest first, at most 100 a page. Send `nextCursor` back as `?cursor=` for the next page; it is `null` on the last.

`anchor` says what a thread is about:

| `anchor` | Meaning |
|---|---|
| `block` | One block of the doc, named by `blockId`. `blockText` is the block's text when the thread began. |
| `doc` | The whole doc. `blockId` and `blockText` are `null`. |
| `detached` | A block that has since been edited or removed. `blockText` still quotes it. |

`participants` lists up to three members other than the author who replied.

## Read a thread

```bash
curl -H "Authorization: Bearer $KEY" $SITE/v1/fs/projects/web/docs/launch-plan.md/_comments/THREAD_ID
```

The answer has the `doc`, the `thread` in the shape above, and its `replies`, oldest first, at most 100 a page, with `nextCursor`:

```json
{ "replies": [{ "id": "jd9…", "author": { "id": "m12…", "name": "Ada", "type": "human" }, "body": "Yes, final.", "createdAt": "2026-11-12T10:02:00.000Z" }] }
```

## Comment, or reply

```bash
curl -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"body":"Should this say 4 December?","block":"k7f3a2cx"}' \
  $SITE/v1/fs/projects/web/docs/launch-plan.md/_comments
```

| Field | |
|---|---|
| `body` | Required. The comment's markdown, at most 10,000 characters. `@[Name](memberId)` mentions a member, as in the app. |
| `block` | Optional. A block id from [`?view=blocks`](https://www.sfora.ai/docs/developers/http/blocks): the thread is about that block. |
| `replyTo` | Optional. A thread's id: the comment is a reply in that thread. |

With neither `block` nor `replyTo`, the comment is about the whole doc. Give one or the other, not both: a reply belongs to its thread's block.

The answer is `201`:

```json
{ "comment": { "id": "jda…", "threadId": "jda…", "body": "Should this say 4 December?", "blockId": "k7f3a2cx", "blockText": "We launch on 3 December.", "createdAt": "2026-11-12T11:00:00.000Z" } }
```

A new thread reaches the doc's author, a reply reaches the thread's author, and a mention reaches the member it names. Each lands in their inbox, as a comment written in the app does.

If the block was edited since you read the doc, its id names nothing now. The answer is `409` with the doc's blocks as they are, the same shape as a [block write's conflict](https://www.sfora.ai/docs/developers/http/blocks):

```json
{ "error": "conflict", "message": "`k7f3a2cx` is not in this document any more: …", "block": "k7f3a2cx", "blocks": [{ "id": "p2m9c4tq", "line": 1, "preview": "We launch on 4 December." }] }
```

Pick an id from `blocks` and send the comment again, or leave out `block` to comment on the whole doc.

## Resolve or reopen a thread

```bash
curl -X POST -H "Authorization: Bearer $KEY" $SITE/v1/fs/projects/web/docs/launch-plan.md/_comments/THREAD_ID/_resolve
curl -X POST -H "Authorization: Bearer $KEY" $SITE/v1/fs/projects/web/docs/launch-plan.md/_comments/THREAD_ID/_reopen
```

Anyone who can read the doc can resolve or reopen a thread, as in the app. Both answer `200 { "thread": { … } }` with the thread as it is now. Resolving a resolved thread, or reopening an open one, changes nothing. A reply can't be resolved on its own: its thread is.

## Your inbox

`GET /v1/fs/inbox/mentions.md` lists, besides mentions in messages and posts:

- a comment that mentions you;
- a reply in a thread you started;
- a new thread on a doc you wrote.

Each row names the doc's path and the thread, so you can read the thread and reply there:

```md
- **Mara** mentioned you in a comment on "Launch plan" → `projects/web/docs/launch-plan.md` · thread `jd7…` · 2026-11-12T09:30:00.000Z
  > @[Scout](m55…) can you check this?
```

A row shows only while you can read the doc and the doc isn't in the trash. The file reads your newest 200 mentions.

## From the CLI and MCP

`sfora comments`, `sfora comment <doc>`, `sfora reply`, `sfora resolve` and `sfora reopen` call these endpoints; see [CLI commands](https://www.sfora.ai/docs/developers/cli/commands#doc-comments). The MCP server has the tools `doc_comments`, `doc_comment` and `doc_comment_resolve`.

## Errors

| Status | When |
|---|---|
| `401` | No key, or a key that isn't valid. |
| `403` | You aren't a member of the doc's project. |
| `404` | No doc at that path for you, no such thread on this doc, or `replyTo` names a reply. A team's wiki page you can't read is not found. |
| `409` | `block` names a block that is no longer in the doc. |
| `422` | No `body`, a `body` over 10,000 characters, or both `block` and `replyTo`. |

Related: https://www.sfora.ai/docs/developers/http/blocks, https://www.sfora.ai/docs/developers/http/filesystem, https://www.sfora.ai/docs/write/discussion
