---
title: Annotation comments
description: Review comments pinned to a single annotation - list, create, edit, resolve, delete. The programmatic side of annotation QA.
section: API Reference
order: 3.5
---
A comment is attached to **one annotation inside one image**, not to the image and
not to the dataset. That is what makes it useful for review: a QA pass can flag the
specific box it disagrees with, and the annotator sees the note on that box in the
editor.

An `@username` mention in the body notifies that member of your organization. See
[Notifications](/docs/api-reference/notifications.md) for reading the resulting feed.

Images are addressed the way you read them off the grid, by **dataset name and
filename**. The annotation itself stays an id: an annotation carries a class name,
not a unique one, so a hundred boxes on an image can all be called `car` and no name
identifies one of them. Take the id from
[`client.annotations.get`](/docs/api-reference/annotations#get).

There is no `pictograph` CLI group for annotation comments; use the Python SDK or
raw REST.

## list

Every comment on the given image's annotations, oldest first, resolved and open
alike.

Source: [`AnnotationComments.list`](https://github.com/pictograph-io/pictograph-sdk/blob/v1.69.67/src/pictograph/resources/annotation_comments.py)

| Arg | Type | Default | Notes |
|---|---|---|---|
| `dataset_name` | `str` | required | Dataset name. |
| `image` | `str` | required | Image filename, or an image id |

```python
comments = client.annotation_comments.list(
    dataset_name="road-signs",
    image="img-001.jpg",
)
for c in comments:
    print(c.id, c.annotation_id, c.resolved, c.body)
```

```bash
curl -s "https://api.pictograph.io/api/v1/developer/annotation-comments?image_id=3f1c8e42-6b90-4a71-9d0e-2b5c7a11e004" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY"
```

**Returns** `Sequence[AnnotationComment]`

<details>
<summary><code>AnnotationComment</code> &middot; 11 fields</summary>

```python
class AnnotationComment(BaseModel):
    """One comment on an annotation."""
    id: str
    annotation_id: str
    body: str
    resolved: bool = False
    created_at: datetime | None = None
    updated_at: datetime | None = None
    user_id: str | None = None
    author_name: str | None = None
    author_username: str | None = None
    author_avatar_url: str | None = None
    is_mine: bool = False
```

</details>

REST takes the image id rather than the filename; resolve one with `GET /api/v1/developer/images/?dataset=road-signs&filename=img-001.jpg`.

## create

Post a comment on one annotation. Requires `member`+ role, and the API key must
belong to a user, since a comment has an author.

Source: [`AnnotationComments.create`](https://github.com/pictograph-io/pictograph-sdk/blob/v1.69.67/src/pictograph/resources/annotation_comments.py)

| Arg | Type | Default | Notes |
|---|---|---|---|
| `dataset_name` | `str` | required | Dataset name. |
| `image` | `str` | required | Image filename, or an image id |
| `annotation_id` | `str` | required | The annotation to pin the comment to |
| `body` | `str` | required | Comment text, 1 to 5000 characters. `@username` mentions notify org members |

```python
annotations = client.annotations.get(
    dataset_name="road-signs",
    image="img-001.jpg",
)
low = [a for a in annotations if (a.confidence or 1.0) < 0.4]

for ann in low:
    client.annotation_comments.create(
        dataset_name="road-signs",
        image="img-001.jpg",
        annotation_id=ann.id,
        body=f"@dana low confidence on this {ann.name} - please re-check.",
    )
```

```bash
curl -s -X POST "https://api.pictograph.io/api/v1/developer/annotation-comments" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "image_id": "3f1c8e42-6b90-4a71-9d0e-2b5c7a11e004",
    "annotation_id": "b41e7d90-5c62-4a38-8e15-9d3f2a7c6b81",
    "body": "@dana low confidence on this stop-sign - please re-check."
  }'
```

**Returns** `AnnotationComment`

<details>
<summary><code>AnnotationComment</code> &middot; 11 fields</summary>

```python
class AnnotationComment(BaseModel):
    """One comment on an annotation."""
    id: str
    annotation_id: str
    body: str
    resolved: bool = False
    created_at: datetime | None = None
    updated_at: datetime | None = None
    user_id: str | None = None
    author_name: str | None = None
    author_username: str | None = None
    author_avatar_url: str | None = None
    is_mine: bool = False
```

</details>

## update

Edit the body, change the resolved flag, or both in one call. Editing the body is
restricted to the comment's author; changing the resolved flag is open to anyone in
the organization. Sending neither field is a 400.

Source: [`AnnotationComments.update`](https://github.com/pictograph-io/pictograph-sdk/blob/v1.69.67/src/pictograph/resources/annotation_comments.py)

| Arg | Type | Default | Notes |
|---|---|---|---|
| `comment_id` | `str` | required | Comment id, from `list` or `create` |
| `body` | `str \| None` | `None` | New text. Author only |
| `resolved` | `bool \| None` | `None` | Mark resolved or reopen |

```python
comment = client.annotation_comments.update(
    comment_id="7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c",
    body="Re-checked against the raw frame - the box is correct after all.",
    resolved=True,
)
print(comment.resolved, comment.updated_at)
```

```bash
curl -s -X PATCH "https://api.pictograph.io/api/v1/developer/annotation-comments/7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY" -H "Content-Type: application/json" \
  -d '{"body": "Re-checked against the raw frame - the box is correct after all.", "resolved": true}'
```

**Returns** `AnnotationComment`

<details>
<summary><code>AnnotationComment</code> &middot; 11 fields</summary>

```python
class AnnotationComment(BaseModel):
    """One comment on an annotation."""
    id: str
    annotation_id: str
    body: str
    resolved: bool = False
    created_at: datetime | None = None
    updated_at: datetime | None = None
    user_id: str | None = None
    author_name: str | None = None
    author_username: str | None = None
    author_avatar_url: str | None = None
    is_mine: bool = False
```

</details>

## resolve

The one-argument form of `update` for the common case: close a comment, or reopen
it with `resolved=False`. It issues the same request.

Source: [`AnnotationComments.resolve`](https://github.com/pictograph-io/pictograph-sdk/blob/v1.69.67/src/pictograph/resources/annotation_comments.py)

| Arg | Type | Default | Notes |
|---|---|---|---|
| `comment_id` | `str` | required | Comment id |
| `resolved` | `bool` | `True` | `False` reopens the comment |

```python
client.annotation_comments.resolve(
    comment_id="7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c",
    resolved=True,
)
```

```bash
curl -s -X PATCH "https://api.pictograph.io/api/v1/developer/annotation-comments/7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY" -H "Content-Type: application/json" \
  -d '{"resolved": true}'
```

**Returns** `AnnotationComment`

<details>
<summary><code>AnnotationComment</code> &middot; 11 fields</summary>

```python
class AnnotationComment(BaseModel):
    """One comment on an annotation."""
    id: str
    annotation_id: str
    body: str
    resolved: bool = False
    created_at: datetime | None = None
    updated_at: datetime | None = None
    user_id: str | None = None
    author_name: str | None = None
    author_username: str | None = None
    author_avatar_url: str | None = None
    is_mine: bool = False
```

</details>

## delete

Remove a comment permanently. Allowed to the author, or to an `admin` / `owner` key
moderating the thread.

Source: [`AnnotationComments.delete`](https://github.com/pictograph-io/pictograph-sdk/blob/v1.69.67/src/pictograph/resources/annotation_comments.py)

| Arg | Type | Default | Notes |
|---|---|---|---|
| `comment_id` | `str` | required | Comment id |

```python
client.annotation_comments.delete(
    comment_id="7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c",
)
```

```bash
curl -s -X DELETE "https://api.pictograph.io/api/v1/developer/annotation-comments/7c2a91d5-4e83-4b16-9f27-8a0d6e3b512c" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY"
```

**Returns** `None`

## Common errors

| Status | Exception | Cause |
|---|---|---|
| 400 | `ValidationError` | `update` sent neither a new body nor a resolved flag, or the API key has no associated user to author a comment |
| 403 | `ForbiddenError` | A `viewer` key tried to comment, a non-author tried to edit a body, or a non-author without `admin`+ tried to delete |
| 404 | `NotFoundError` | The image or the comment does not exist in your organization |