# Plan · Comments & files

> Comments, reactions, attachments, and each task's activity feed and event log. Part of the Dailybot Plan API (Beta).

Language: en
Canonical: https://www.dailybot.com/developers/api/plan-collaboration
Markdown: send header `Accept: text/markdown` on any URL to receive Markdown instead of HTML.
Last Updated: 2026-09-25

---

> **Beta** — Plan is in beta. Everything under `/plan` in the web app, the CLI and agent skill commands for projects, goals, boards and tasks, and the `/v1/plan/` public API may change before general availability. Want to try it with your team? Write to **support@dailybot.com**.

This page is the reference for **Plan · Comments & files**. Every endpoint lives under `https://api.dailybot.com/v1/plan/` and answers JSON.

Authenticate with a login session or a CLI user token (`Authorization: Bearer …`), or with an API key (`X-API-KEY`). A **personal API key** acts as its person and can do everything that person can do in Dailybot; an **agent or organization key** never acts as a person and is refused on the endpoints that need one. On an endpoint, the *API key* badge means an agent or organization key is accepted too. See [Authentication for Plan](/developers/plan/authentication), [Authentication](/developers/authentication) and [Errors](/developers/errors) for the rules shared by every Dailybot API.

New to Plan? Read the [overview](/developers/plan) for the model: projects, boards, workflow states, keys, ordering, versions and archive.

## Endpoints in this group

Comments, reactions, attachments, and each task's activity feed and event log. Part of the Dailybot Plan API (Beta).

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/v1/plan/tasks/{task_id}/comments/` | List a task's comments |
| POST | `/v1/plan/tasks/{task_id}/comments/` | Comment on a task |
| PATCH | `/v1/plan/tasks/{task_id}/comments/{comment_id}/` | Edit a comment |
| DELETE | `/v1/plan/tasks/{task_id}/comments/{comment_id}/` | Delete a comment |
| POST | `/v1/plan/tasks/{task_id}/comments/{comment_id}/reactions/` | Add an emoji reaction to a comment (idempotent) |
| DELETE | `/v1/plan/tasks/{task_id}/comments/{comment_id}/reactions/{emoji}/` | Remove the caller's emoji reaction from a comment |
| GET | `/v1/plan/tasks/{task_id}/comments/{comment_id}/attachments/` | List a comment's attachments |
| POST | `/v1/plan/tasks/{task_id}/comments/{comment_id}/attachments/` | Upload an attachment to a comment |
| GET | `/v1/plan/tasks/{task_id}/comments/{comment_id}/attachments/{attachment_id}/content/` | Download a comment attachment's bytes |
| DELETE | `/v1/plan/tasks/{task_id}/comments/{comment_id}/attachments/{attachment_id}/` | Remove an attachment from a comment |
| GET | `/v1/plan/tasks/{task_id}/attachments/` | List a task's attachments |
| POST | `/v1/plan/tasks/{task_id}/attachments/` | Upload an attachment in one request |
| POST | `/v1/plan/tasks/{task_id}/attachments/presign/` | Reserve an attachment and receive an upload target |
| GET | `/v1/plan/tasks/{task_id}/attachments/{attachment_id}/content/` | Download an attachment's bytes through the API |
| PUT | `/v1/plan/tasks/{task_id}/attachments/{attachment_id}/content/` | Upload bytes for a presigned attachment (local/dev fallback) |
| POST | `/v1/plan/tasks/{task_id}/attachments/{attachment_id}/confirm/` | Mark a presigned attachment ready after upload |
| DELETE | `/v1/plan/tasks/{task_id}/attachments/{attachment_id}/` | Remove an attachment |
| GET | `/v1/plan/tasks/{task_id}/events/` | A task's activity, rendered from the event log |
| GET | `/v1/plan/tasks/{task_id}/activity/` | A task's activity feed, enriched for display |
| GET | `/v1/plan/attachments/resolve/` | Resolve attachment references |
| PATCH | `/v1/plan/tasks/{task_id}/comments/{comment_id}/attachments/{attachment_id}/` | Rename a comment attachment |
| GET | `/v1/plan/tasks/{task_id}/comments/{comment_id}/reactions/` | List who reacted to a comment |

### GET `/v1/plan/tasks/{task_id}/comments/` · Beta

**List a task's comments**

The task's comments, oldest first, as a page. Each comment carries its reactions and its ready `attachments`. Use `updated_since` to fetch only what changed since your last read.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (read)
- **Rate limit:** `default`
- **Pagination:** Page-number pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |

#### Query parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `page` | integer | No | 1-based page number. |
| `page_size` | integer | No | Rows per page. Default 50, maximum 100. Out-of-range values are clamped, never rejected: asking for 500 returns 100. |
| `updated_since` | string | No | A timestamp filter on this paginated list: it returns `{count, next, previous, results}`, never a cursor. For a change feed use the board delta endpoint. |

#### TaskComment object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `uuid` | uuid | Yes | Stable public identifier. |
| `body` | string | Yes | Markdown as typed. Mention someone with `<@DB@{uuid}>`, using a `uuid` from the mentionables list. Max 10000 characters. |
| `author` | ActorRef | null | Yes | Who wrote the comment. See [ActorRef](#plan-task-comments-list-actorref). |
| `executed_by_agent` | object | null | No | The agent that executed this on behalf of the person, or `null` when no agent was named: an object with `uuid`, `name`, `username` and `avatar`. The person in the author field is still the author; the agent is shown as the one who executed it. |
| `mentions` | array<ActorRef> | No | The people mentioned. Read them from here, never by parsing `body`. See [ActorRef](#plan-task-comments-list-actorref). |
| `body_html` | string | No | `body` rendered and sanitized by the server. Client HTML is never accepted. |
| `reactions` | array | No | Emoji reactions, with whether you reacted. All fields are always present. Items: `{emoji: string, count: integer, reacted: boolean}`. |
| `provenance` | enum | Yes | `typed` by a person, `agent_authored`, or `retrieved` from another system. One of `typed`, `agent_authored`, `retrieved`. |
| `parent_comment` | uuid | null | No | The comment this one replies to. One level of threading only. |
| `edited_at` | date-time | null | No | When the comment was last edited. |
| `is_deleted` | boolean | No | Deleted comments keep their row with a blank body. |
| `created_at` | date-time | Yes | When the row was created. |
| `attachments` | array<TaskAttachment> | No | The comment's ready attachments, ordered by position. See [TaskAttachment](#plan-task-comments-list-taskattachment). |

#### ActorRef object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `kind` | string | Yes | — |
| `uuid` | string | Yes | Stable public identifier. |
| `name` | string | No | Display name. |
| `username` | string | null | No | — |
| `avatar_url` | string | null | No | — |
| `has_photo` | boolean | No | — |

#### TaskAttachment object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `uuid` | uuid | Yes | Stable public identifier. |
| `filename` | string | Yes | File name. |
| `content_type` | string | Yes | MIME type. |
| `size` | integer | Yes | Size in bytes. |
| `url` | string | Yes | Where to download the file. |
| `thumbnail_url` | uri | null | No | Thumbnail for images. |
| `width` | integer | null | No | — |
| `height` | integer | null | No | — |
| `status` | enum | Yes | Current status. One of `pending`, `ready`, `scanning`, `rejected`. |
| `uploaded_by` | ActorRef | null | No | Who uploaded the file. See [ActorRef](#plan-task-comments-list-actorref). |
| `executed_by_agent` | object | null | No | The agent that executed this on behalf of the person, or `null` when no agent was named: an object with `uuid`, `name`, `username` and `avatar`. The person in the author field is still the author; the agent is shown as the one who executed it. |
| `created_at` | date-time | Yes | When the row was created. |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `count` | integer | Yes | Total number of rows. |
| `next` | uri | Yes | URL of the next page, or `null`. |
| `previous` | uri | Yes | URL of the previous page, or `null`. |
| `results` | array<TaskComment> | Yes | The rows on this page. See [TaskComment](#plan-task-comments-list-taskcomment). |

#### Error codes

| Status | When |
|--------|------|
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `404` | Not found, or not visible to you. Both cases return the same body. |

#### Example (curl)

```bash
curl -sS "https://api.dailybot.com/v1/plan/tasks/ENG-142/comments/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan task comments ENG-142 --json
```

##### Response

```bash
{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "uuid": "00000000-0000-4000-8000-000000000008",
      "body": "Staging is green; rolling out Friday.",
      "author": {
        "kind": "user",
        "uuid": "00000000-0000-4000-8000-00000000000c",
        "name": "Ada L."
      },
      "mentions": [],
      "body_html": "<p>Staging is green; rolling out Friday.</p>",
      "reactions": [],
      "provenance": "typed",
      "parent_comment": null,
      "edited_at": null,
      "is_deleted": false,
      "created_at": "2026-09-25T10:14:02Z",
      "attachments": []
    }
  ]
}
```

#### Notes

- Scope: `tasks:read`.
- Rate limit: 120 reads per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### POST `/v1/plan/tasks/{task_id}/comments/` · Beta

**Comment on a task**

Adds a comment to the task. Mention someone with `<@DB@{uuid}>`, using a `uuid` from the board's mentionables. Send an `Idempotency-Key` to retry safely.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |

#### Headers

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `Idempotency-Key` | string | No | A key you generate for this intent. A replay with the same key and body returns the first response without a second side effect and carries `Idempotency-Replayed: true`. Keys are kept for 24 hours. The same key with a different body is `409 idempotency_key_payload_mismatch`; a repeat while the first call is still running gets `409 idempotency_in_progress` for up to 120 seconds. |
| `X-Dailybot-Agent-Name` | string | No | The name of the agent that executed this write on the person's behalf. Use it on multipart and body-less writes (DELETE, archive, restore); on JSON writes send the body field `agent_name` instead, which wins if both are present. Percent-encode the value as UTF-8. Control characters are stripped; a blank value means no agent. More than 128 characters, or a value that cannot be decoded, is `400 invalid_agent_attribution` (never truncated). An agent-type key, which is not bound to a person, gets `400 invalid_agent_attribution` if it sends it. The stamp never changes a permission answer. See [Agent attribution](/developers/plan/conventions#agent-attribution). |

#### Request body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `body` | string | Yes | Markdown. Mention someone with `<@DB@{uuid}>`, using a `uuid` from the mentionables list. Max 10000 characters. |
| `parent_comment` | uuid | null | No | The comment this one replies to. One level of threading only. |
| `agent_name` | string | No | The name of the agent that executed this write on the person's behalf (max 128 characters, blank means no agent). Takes priority over the `X-Dailybot-Agent-Name` header. See [Agent attribution](/developers/plan/conventions#agent-attribution). |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `(body)` | TaskComment | Yes | A [TaskComment](#plan-task-comments-list-taskcomment) object. |

#### Error codes

| Status | When |
|--------|------|
| `400` | Validation failed, or a filter, sort or `include` value was not recognised. The response `code` says which. `invalid_agent_attribution` means the agent name is invalid. |
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `404` | Not found, or not visible to you. Both cases return the same body. |

#### Example (curl)

```bash
curl -sS -X POST "https://api.dailybot.com/v1/plan/tasks/ENG-142/comments/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Looks good. <@DB@00000000-0000-4000-8000-00000000000c> can you review the rollout plan?"
  }'
```

#### Scenario examples

##### CLI

```bash
dailybot plan task comment ENG-142 "Deployed. <@DB@00000000-0000-4000-8000-00000000000c> can you verify?"
```

#### Notes

- Scope: `tasks:write`.
- Rate limit: 60 writes per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### PATCH `/v1/plan/tasks/{task_id}/comments/{comment_id}/` · Beta

**Edit a comment**

Edits a comment's body. Only its author can edit it (`403 comment_not_author`); the response sets `edited_at`.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |
| `comment_id` | string | Yes | The comment's uuid. |

#### Headers

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `X-Dailybot-Agent-Name` | string | No | The name of the agent that executed this write on the person's behalf. Use it on multipart and body-less writes (DELETE, archive, restore); on JSON writes send the body field `agent_name` instead, which wins if both are present. Percent-encode the value as UTF-8. Control characters are stripped; a blank value means no agent. More than 128 characters, or a value that cannot be decoded, is `400 invalid_agent_attribution` (never truncated). An agent-type key, which is not bound to a person, gets `400 invalid_agent_attribution` if it sends it. The stamp never changes a permission answer. See [Agent attribution](/developers/plan/conventions#agent-attribution). |

#### Request body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `body` | string | Yes | Markdown. Mention someone with `<@DB@{uuid}>`, using a `uuid` from the mentionables list. Max 10000 characters. |
| `parent_comment` | uuid | null | No | The comment this one replies to. One level of threading only. |
| `agent_name` | string | No | The name of the agent that executed this write on the person's behalf (max 128 characters, blank means no agent). Takes priority over the `X-Dailybot-Agent-Name` header. See [Agent attribution](/developers/plan/conventions#agent-attribution). |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `(body)` | TaskComment | Yes | A [TaskComment](#plan-task-comments-list-taskcomment) object. |

#### Error codes

| Status | When |
|--------|------|
| `400` | The agent name is invalid (`invalid_agent_attribution`). |
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `403` | Authenticated but not allowed: missing scope (`insufficient_scope`, which is also what an agent or organization key gets on an operation that needs a person, and what a personal key gets when its explicit Plan scopes do not cover the endpoint) or a guest account (`guest_not_allowed`). |
| `404` | Not found, or not visible to you. Both cases return the same body. |

#### Example (curl)

```bash
curl -sS -X PATCH "https://api.dailybot.com/v1/plan/tasks/ENG-142/comments/00000000-0000-4000-8000-000000000008/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Looks good. Rollout plan attached."
  }'
```

#### Scenario examples

##### CLI

```bash
dailybot plan task comment-edit ENG-142 00000000-0000-4000-8000-000000000008 "Deployed to production"
```

#### Notes

- Scope: `tasks:write`.
- Rate limit: 60 writes per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### DELETE `/v1/plan/tasks/{task_id}/comments/{comment_id}/` · Beta

**Delete a comment**

A soft delete: the row survives so its events keep resolving, and the body is blanked.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |
| `comment_id` | string | Yes | The comment's uuid. |

#### Headers

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `X-Dailybot-Agent-Name` | string | No | The name of the agent that executed this write on the person's behalf. Use it on multipart and body-less writes (DELETE, archive, restore); on JSON writes send the body field `agent_name` instead, which wins if both are present. Percent-encode the value as UTF-8. Control characters are stripped; a blank value means no agent. More than 128 characters, or a value that cannot be decoded, is `400 invalid_agent_attribution` (never truncated). An agent-type key, which is not bound to a person, gets `400 invalid_agent_attribution` if it sends it. The stamp never changes a permission answer. See [Agent attribution](/developers/plan/conventions#agent-attribution). |

#### Error codes

| Status | When |
|--------|------|
| `400` | The agent name is invalid (`invalid_agent_attribution`). |
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `403` | Authenticated but not allowed: missing scope (`insufficient_scope`, which is also what an agent or organization key gets on an operation that needs a person, and what a personal key gets when its explicit Plan scopes do not cover the endpoint) or a guest account (`guest_not_allowed`). |
| `404` | Not found, or not visible to you. Both cases return the same body. |

#### Example (curl)

```bash
curl -sS -X DELETE "https://api.dailybot.com/v1/plan/tasks/ENG-142/comments/00000000-0000-4000-8000-000000000008/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan task comment-delete ENG-142 00000000-0000-4000-8000-000000000008 --yes
```

#### Notes

- Scope: `tasks:write`.
- Rate limit: 60 writes per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### POST `/v1/plan/tasks/{task_id}/comments/{comment_id}/reactions/` · Beta

**Add an emoji reaction to a comment (idempotent)**

Adds your `emoji` reaction to the comment. It is idempotent: adding the same reaction again changes nothing. The response is the comment with its updated reactions.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |
| `comment_id` | string | Yes | The comment's uuid. |

#### Headers

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `X-Dailybot-Agent-Name` | string | No | The name of the agent that executed this write on the person's behalf. Use it on multipart and body-less writes (DELETE, archive, restore); on JSON writes send the body field `agent_name` instead, which wins if both are present. Percent-encode the value as UTF-8. Control characters are stripped; a blank value means no agent. More than 128 characters, or a value that cannot be decoded, is `400 invalid_agent_attribution` (never truncated). An agent-type key, which is not bound to a person, gets `400 invalid_agent_attribution` if it sends it. The stamp never changes a permission answer. See [Agent attribution](/developers/plan/conventions#agent-attribution). |

#### Request body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `emoji` | string | Yes | The emoji. Max 32 characters. |
| `agent_name` | string | No | The name of the agent that executed this write on the person's behalf (max 128 characters, blank means no agent). Takes priority over the `X-Dailybot-Agent-Name` header. See [Agent attribution](/developers/plan/conventions#agent-attribution). |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `(body)` | TaskComment | Yes | A [TaskComment](#plan-task-comments-list-taskcomment) object. |

#### Error codes

| Status | When |
|--------|------|
| `400` | Validation failed, or a filter, sort or `include` value was not recognised. The response `code` says which. `invalid_agent_attribution` means the agent name is invalid. |
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `404` | Not found, or not visible to you. Both cases return the same body. |

#### Example (curl)

```bash
curl -sS -X POST "https://api.dailybot.com/v1/plan/tasks/ENG-142/comments/00000000-0000-4000-8000-000000000008/reactions/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "emoji": "👍"
  }'
```

#### Notes

- Scope: `tasks:write`.
- Rate limit: 60 writes per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### DELETE `/v1/plan/tasks/{task_id}/comments/{comment_id}/reactions/{emoji}/` · Beta

**Remove the caller's emoji reaction from a comment**

Removes your reaction with this emoji from the comment. It answers `204` even when the reaction was already gone.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |
| `comment_id` | string | Yes | The comment's uuid. |
| `emoji` | string | Yes | The emoji to remove, as sent when adding it (max 32 characters), URL-encoded in the path. |

#### Headers

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `X-Dailybot-Agent-Name` | string | No | The name of the agent that executed this write on the person's behalf. Use it on multipart and body-less writes (DELETE, archive, restore); on JSON writes send the body field `agent_name` instead, which wins if both are present. Percent-encode the value as UTF-8. Control characters are stripped; a blank value means no agent. More than 128 characters, or a value that cannot be decoded, is `400 invalid_agent_attribution` (never truncated). An agent-type key, which is not bound to a person, gets `400 invalid_agent_attribution` if it sends it. The stamp never changes a permission answer. See [Agent attribution](/developers/plan/conventions#agent-attribution). |

#### Error codes

| Status | When |
|--------|------|
| `400` | Validation failed, or a filter, sort or `include` value was not recognised. The response `code` says which. `invalid_agent_attribution` means the agent name is invalid. |
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `404` | Not found, or not visible to you. Both cases return the same body. |

#### Example (curl)

```bash
curl -sS -X DELETE "https://api.dailybot.com/v1/plan/tasks/ENG-142/comments/00000000-0000-4000-8000-000000000008/reactions/%F0%9F%91%8D/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Notes

- Scope: `tasks:write`.
- Rate limit: 60 writes per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### GET `/v1/plan/tasks/{task_id}/comments/{comment_id}/attachments/` · Beta

**List a comment's attachments**

The comment's attachments, ordered by position. The comment itself already carries its ready attachments in `attachments`. Each `url` is a download link. Do not store it: keep the attachment `uuid` and read it again when you need the file.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (read)
- **Rate limit:** `default`
- **Pagination:** Page-number pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |
| `comment_id` | string | Yes | The comment's uuid. |

#### Query parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `page` | integer | No | 1-based page number. |
| `page_size` | integer | No | Rows per page. Default 50, maximum 100. Out-of-range values are clamped, never rejected: asking for 500 returns 100. |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `count` | integer | Yes | Total number of rows. |
| `next` | uri | Yes | URL of the next page, or `null`. |
| `previous` | uri | Yes | URL of the previous page, or `null`. |
| `results` | array<TaskAttachment> | Yes | The rows on this page. See [TaskAttachment](#plan-task-comments-list-taskattachment). |

#### Error codes

| Status | When |
|--------|------|
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `404` | The task, comment or attachment does not exist or you cannot see it (`not_found`), never a 403. |

#### Example (curl)

```bash
curl -sS "https://api.dailybot.com/v1/plan/tasks/ENG-142/comments/00000000-0000-4000-8000-000000000008/attachments/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan task comment-attachments ENG-142 00000000-0000-4000-8000-000000000008 --json
```

##### Response

```bash
{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "uuid": "00000000-0000-4000-8000-000000000009",
      "filename": "screenshot.png",
      "content_type": "image/png",
      "size": 1,
      "url": "https://your.app/files/screenshot.png",
      "thumbnail_url": null,
      "width": null,
      "height": null,
      "status": "ready",
      "uploaded_by": {
        "kind": "user",
        "uuid": "00000000-0000-4000-8000-00000000000c",
        "name": "Ada L."
      },
      "created_at": "2026-09-25T10:14:02Z"
    }
  ]
}
```

#### Notes

- Scope: `tasks:read`.
- Rate limit: 120 reads per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### POST `/v1/plan/tasks/{task_id}/comments/{comment_id}/attachments/` · Beta

**Upload an attachment to a comment**

Attach a file to a comment. Only the comment's author can attach to it. Send `multipart/form-data` with the `file` field and an optional `caption`; there is no presign flow here. The limit is **5 MiB** in every environment: a larger file is `400 attachment_too_large`, with `extra.max_size_bytes`. The file type is checked from its content against the same list as task attachments (`attachment_invalid_type`). A comment holds at most 50 attachments (`attachment_limit_reached`).

- **Auth:** API key (`X-API-KEY`), CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |
| `comment_id` | string | Yes | The comment's uuid. |

#### Headers

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `X-Dailybot-Agent-Name` | string | No | The name of the agent that executed this write on the person's behalf. Use it on multipart and body-less writes (DELETE, archive, restore); on JSON writes send the body field `agent_name` instead, which wins if both are present. Percent-encode the value as UTF-8. Control characters are stripped; a blank value means no agent. More than 128 characters, or a value that cannot be decoded, is `400 invalid_agent_attribution` (never truncated). An agent-type key, which is not bound to a person, gets `400 invalid_agent_attribution` if it sends it. The stamp never changes a permission answer. See [Agent attribution](/developers/plan/conventions#agent-attribution). |

#### Request body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `file` | binary | Yes | The file to upload (max 5 MiB this way). |
| `caption` | string | No | Optional caption. Max 255 characters. |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `(body)` | TaskAttachment | Yes | A [TaskAttachment](#plan-task-comments-list-taskattachment) object. |

#### Error codes

| Status | When |
|--------|------|
| `400` | The file is missing, too large (`attachment_too_large`, over 5 MiB), of an unsupported type (`attachment_invalid_type`), or the limit of 50 is reached (`attachment_limit_reached`). `invalid_agent_attribution` means the agent name is invalid. |
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `403` | You are not the comment's author (`comment_not_author`). |
| `404` | The task, comment or attachment does not exist or you cannot see it (`not_found`), never a 403. |

#### Example (curl)

```bash
curl -sS -X POST "https://api.dailybot.com/v1/plan/tasks/ENG-142/comments/00000000-0000-4000-8000-000000000008/attachments/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY" \
  -F "file=@./screenshot.png" \
  -F "caption=Staging dashboard"
```

#### Scenario examples

##### CLI

```bash
dailybot plan task comment-attach ENG-142 00000000-0000-4000-8000-000000000008 ./trace.txt --caption "Stack trace"
```

#### Notes

- Scope: `tasks:write`.
- Rate limit: 60 writes per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### GET `/v1/plan/tasks/{task_id}/comments/{comment_id}/attachments/{attachment_id}/content/` · Beta

**Download a comment attachment's bytes**

Streams the file with the content type recorded at upload, `X-Content-Type-Options: nosniff` and `Cache-Control: no-store`. It never redirects to storage. Authorized like every other read of the task.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (read)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |
| `comment_id` | string | Yes | The comment's uuid. |
| `attachment_id` | string | Yes | The attachment's uuid. |

#### Error codes

| Status | When |
|--------|------|
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `404` | The task, comment or attachment does not exist or you cannot see it (`not_found`), never a 403. |

#### Example (curl)

```bash
curl -sS "https://api.dailybot.com/v1/plan/tasks/ENG-142/comments/00000000-0000-4000-8000-000000000008/attachments/00000000-0000-4000-8000-000000000009/content/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan task comment-attachment get ENG-142 00000000-0000-4000-8000-000000000008 00000000-0000-4000-8000-000000000009 -o ./trace.txt
```

#### Notes

- Scope: `tasks:read`.
- Rate limit: 120 reads per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### DELETE `/v1/plan/tasks/{task_id}/comments/{comment_id}/attachments/{attachment_id}/` · Beta

**Remove an attachment from a comment**

Removes the attachment from the comment. Allowed for the person who uploaded it, the comment's author or an organization admin.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |
| `comment_id` | string | Yes | The comment's uuid. |
| `attachment_id` | string | Yes | The attachment's uuid. |

#### Headers

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `X-Dailybot-Agent-Name` | string | No | The name of the agent that executed this write on the person's behalf. Use it on multipart and body-less writes (DELETE, archive, restore); on JSON writes send the body field `agent_name` instead, which wins if both are present. Percent-encode the value as UTF-8. Control characters are stripped; a blank value means no agent. More than 128 characters, or a value that cannot be decoded, is `400 invalid_agent_attribution` (never truncated). An agent-type key, which is not bound to a person, gets `400 invalid_agent_attribution` if it sends it. The stamp never changes a permission answer. See [Agent attribution](/developers/plan/conventions#agent-attribution). |

#### Error codes

| Status | When |
|--------|------|
| `400` | The agent name is invalid (`invalid_agent_attribution`). |
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `403` | You are not the uploader, the comment's author or an organization admin (`attachment_delete_forbidden`). |
| `404` | The task, comment or attachment does not exist or you cannot see it (`not_found`), never a 403. |

#### Example (curl)

```bash
curl -sS -X DELETE "https://api.dailybot.com/v1/plan/tasks/ENG-142/comments/00000000-0000-4000-8000-000000000008/attachments/00000000-0000-4000-8000-000000000009/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan task comment-attachment delete ENG-142 00000000-0000-4000-8000-000000000008 00000000-0000-4000-8000-000000000009 --yes
```

#### Notes

- Scope: `tasks:write`.
- Rate limit: 60 writes per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### GET `/v1/plan/tasks/{task_id}/attachments/` · Beta

**List a task's attachments**

The task's attachments, ordered by position, as a page. Each `url` is a download link; do not store it. Read the attachment again for the current one, or download through the content endpoint.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (read)
- **Rate limit:** `default`
- **Pagination:** Page-number pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |

#### Query parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `page` | integer | No | 1-based page number. |
| `page_size` | integer | No | Rows per page. Default 50, maximum 100. Out-of-range values are clamped, never rejected: asking for 500 returns 100. |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `count` | integer | Yes | Total number of rows. |
| `next` | uri | Yes | URL of the next page, or `null`. |
| `previous` | uri | Yes | URL of the previous page, or `null`. |
| `results` | array<TaskAttachment> | Yes | The rows on this page. See [TaskAttachment](#plan-task-comments-list-taskattachment). |

#### Error codes

| Status | When |
|--------|------|
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `404` | Not found, or not visible to you. Both cases return the same body. |

#### Example (curl)

```bash
curl -sS "https://api.dailybot.com/v1/plan/tasks/ENG-142/attachments/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan task attachments ENG-142 --json
```

#### Notes

- Scope: `tasks:read`.
- Rate limit: 120 reads per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### POST `/v1/plan/tasks/{task_id}/attachments/` · Beta

**Upload an attachment in one request**

Upload a file in one request, up to 5 MiB. For files up to 25 MiB, use presign → upload → confirm.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |

#### Headers

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `X-Dailybot-Agent-Name` | string | No | The name of the agent that executed this write on the person's behalf. Use it on multipart and body-less writes (DELETE, archive, restore); on JSON writes send the body field `agent_name` instead, which wins if both are present. Percent-encode the value as UTF-8. Control characters are stripped; a blank value means no agent. More than 128 characters, or a value that cannot be decoded, is `400 invalid_agent_attribution` (never truncated). An agent-type key, which is not bound to a person, gets `400 invalid_agent_attribution` if it sends it. The stamp never changes a permission answer. See [Agent attribution](/developers/plan/conventions#agent-attribution). |

#### Request body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `file` | binary | Yes | The file to upload (max 5 MiB this way). |
| `caption` | string | No | Optional caption. Max 255 characters. |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `(body)` | TaskAttachment | Yes | A [TaskAttachment](#plan-task-comments-list-taskattachment) object. |

#### Error codes

| Status | When |
|--------|------|
| `400` | Validation failed, or a filter, sort or `include` value was not recognised. The response `code` says which. `invalid_agent_attribution` means the agent name is invalid. |
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `404` | Not found, or not visible to you. Both cases return the same body. |

#### Example (curl)

```bash
curl -sS -X POST "https://api.dailybot.com/v1/plan/tasks/ENG-142/attachments/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY" \
  -F "file=@./screenshot.png" \
  -F "caption=Staging dashboard"
```

#### Scenario examples

##### CLI

```bash
dailybot plan task attach ENG-142 ./screenshot.png --caption "Staging dashboard"
```

#### Notes

- Scope: `tasks:write`.
- Rate limit: 60 writes per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### POST `/v1/plan/tasks/{task_id}/attachments/presign/` · Beta

**Reserve an attachment and receive an upload target**

Reserve an attachment and get an upload target. The declared `size` may be up to 25 MiB when the server has object storage; otherwise uploads are capped at 5 MiB and larger declarations are refused with `attachment_too_large`.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |

#### Headers

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `X-Dailybot-Agent-Name` | string | No | The name of the agent that executed this write on the person's behalf. Use it on multipart and body-less writes (DELETE, archive, restore); on JSON writes send the body field `agent_name` instead, which wins if both are present. Percent-encode the value as UTF-8. Control characters are stripped; a blank value means no agent. More than 128 characters, or a value that cannot be decoded, is `400 invalid_agent_attribution` (never truncated). An agent-type key, which is not bound to a person, gets `400 invalid_agent_attribution` if it sends it. The stamp never changes a permission answer. See [Agent attribution](/developers/plan/conventions#agent-attribution). |

#### Request body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `filename` | string | Yes | File name. Max 255 characters. |
| `content_type` | string | Yes | MIME type. Max 127 characters. |
| `size` | integer | Yes | Size in bytes. From 1 to 26214400. |
| `agent_name` | string | No | The name of the agent that executed this write on the person's behalf (max 128 characters, blank means no agent). Takes priority over the `X-Dailybot-Agent-Name` header. See [Agent attribution](/developers/plan/conventions#agent-attribution). |

#### TaskAttachmentPresignResponse object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `upload_url` | string | Yes | Where to upload the bytes. |
| `method` | string | Yes | HTTP method for the upload. |
| `headers` | object | Yes | Headers to send with the upload. |
| `expires_in` | integer | Yes | Seconds until the upload target expires. |
| `attachment` | TaskAttachment | Yes | The pending attachment. See [TaskAttachment](#plan-task-comments-list-taskattachment). |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `(body)` | TaskAttachmentPresignResponse | Yes | A [TaskAttachmentPresignResponse](#plan-task-attachment-presign-taskattachmentpresignresponse) object. |

#### Error codes

| Status | When |
|--------|------|
| `400` | Validation failed, or a filter, sort or `include` value was not recognised. The response `code` says which. `invalid_agent_attribution` means the agent name is invalid. |
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `404` | Not found, or not visible to you. Both cases return the same body. |

#### Example (curl)

```bash
curl -sS -X POST "https://api.dailybot.com/v1/plan/tasks/ENG-142/attachments/presign/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filename": "screenshot.png",
    "content_type": "image/png",
    "size": 482133
  }'
```

#### Scenario examples

##### CLI

```bash
dailybot plan task attach ENG-142 ./screenshot.png
```

##### Response

```bash
{
  "upload_url": "https://your.app/files/screenshot.png",
  "method": "PUT",
  "headers": {},
  "expires_in": 900,
  "attachment": {
    "uuid": "00000000-0000-4000-8000-000000000009",
    "filename": "screenshot.png",
    "content_type": "image/png",
    "size": 1,
    "url": "https://your.app/files/screenshot.png",
    "thumbnail_url": null,
    "width": null,
    "height": null,
    "status": "ready",
    "uploaded_by": {
      "kind": "user",
      "uuid": "00000000-0000-4000-8000-00000000000c",
      "name": "Ada L."
    },
    "created_at": "2026-09-25T10:14:02Z"
  }
}
```

#### Notes

- Scope: `tasks:write`.
- Rate limit: 60 writes per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### GET `/v1/plan/tasks/{task_id}/attachments/{attachment_id}/content/` · Beta

**Download an attachment's bytes through the API**

Streams the file, authorized like every other read of the task. On servers without object storage, this is the attachment's `url`; otherwise `url` is a download link and this endpoint is the alternative for clients that prefer to send their credential. `409 attachment_not_ready` if the upload was never completed.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (read)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |
| `attachment_id` | string | Yes | The attachment's uuid. |

#### Error codes

| Status | When |
|--------|------|
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `404` | Not found, or not visible to you. Both cases return the same body. |
| `409` | The upload was never completed or confirmed (`attachment_not_ready`). |

#### Example (curl)

```bash
curl -sS "https://api.dailybot.com/v1/plan/tasks/ENG-142/attachments/00000000-0000-4000-8000-000000000009/content/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan task attachment get ENG-142 00000000-0000-4000-8000-000000000009 -o ./screenshot.png
```

#### Notes

- Scope: `tasks:read`.
- Rate limit: 120 reads per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### PUT `/v1/plan/tasks/{task_id}/attachments/{attachment_id}/content/` · Beta

**Upload bytes for a presigned attachment (local/dev fallback)**

Upload the bytes for a presigned attachment when the upload target points back at the API (servers without object storage). Capped at 5 MiB.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |
| `attachment_id` | string | Yes | The attachment's uuid. |

#### Headers

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `X-Dailybot-Agent-Name` | string | No | The name of the agent that executed this write on the person's behalf. Use it on multipart and body-less writes (DELETE, archive, restore); on JSON writes send the body field `agent_name` instead, which wins if both are present. Percent-encode the value as UTF-8. Control characters are stripped; a blank value means no agent. More than 128 characters, or a value that cannot be decoded, is `400 invalid_agent_attribution` (never truncated). An agent-type key, which is not bound to a person, gets `400 invalid_agent_attribution` if it sends it. The stamp never changes a permission answer. See [Agent attribution](/developers/plan/conventions#agent-attribution). |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `(body)` | TaskAttachment | Yes | A [TaskAttachment](#plan-task-comments-list-taskattachment) object. |

#### Error codes

| Status | When |
|--------|------|
| `400` | Validation failed, or a filter, sort or `include` value was not recognised. The response `code` says which. `invalid_agent_attribution` means the agent name is invalid. |
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `404` | Not found, or not visible to you. Both cases return the same body. |

#### Example (curl)

```bash
curl -sS -X PUT "https://api.dailybot.com/v1/plan/tasks/ENG-142/attachments/00000000-0000-4000-8000-000000000009/content/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY" \
  -H "Content-Type: image/png" \
  --data-binary @./screenshot.png
```

#### Notes

- Scope: `tasks:write`.
- Rate limit: 60 writes per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### POST `/v1/plan/tasks/{task_id}/attachments/{attachment_id}/confirm/` · Beta

**Mark a presigned attachment ready after upload**

The last step of presign → upload → confirm: marks the attachment ready once its bytes are uploaded. Until then, downloading it answers `409 attachment_not_ready`.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |
| `attachment_id` | string | Yes | The attachment's uuid. |

#### Headers

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `X-Dailybot-Agent-Name` | string | No | The name of the agent that executed this write on the person's behalf. Use it on multipart and body-less writes (DELETE, archive, restore); on JSON writes send the body field `agent_name` instead, which wins if both are present. Percent-encode the value as UTF-8. Control characters are stripped; a blank value means no agent. More than 128 characters, or a value that cannot be decoded, is `400 invalid_agent_attribution` (never truncated). An agent-type key, which is not bound to a person, gets `400 invalid_agent_attribution` if it sends it. The stamp never changes a permission answer. See [Agent attribution](/developers/plan/conventions#agent-attribution). |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `(body)` | TaskAttachment | Yes | A [TaskAttachment](#plan-task-comments-list-taskattachment) object. |

#### Error codes

| Status | When |
|--------|------|
| `400` | The agent name is invalid (`invalid_agent_attribution`). |
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `404` | Not found, or not visible to you. Both cases return the same body. |

#### Example (curl)

```bash
curl -sS -X POST "https://api.dailybot.com/v1/plan/tasks/ENG-142/attachments/00000000-0000-4000-8000-000000000009/confirm/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan task attach ENG-142 ./screenshot.png
```

#### Notes

- Scope: `tasks:write`.
- Rate limit: 60 writes per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### DELETE `/v1/plan/tasks/{task_id}/attachments/{attachment_id}/` · Beta

**Remove an attachment**

Removes the attachment from the task. The stored file is deleted when nothing else references it.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |
| `attachment_id` | string | Yes | The attachment's uuid. |

#### Headers

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `X-Dailybot-Agent-Name` | string | No | The name of the agent that executed this write on the person's behalf. Use it on multipart and body-less writes (DELETE, archive, restore); on JSON writes send the body field `agent_name` instead, which wins if both are present. Percent-encode the value as UTF-8. Control characters are stripped; a blank value means no agent. More than 128 characters, or a value that cannot be decoded, is `400 invalid_agent_attribution` (never truncated). An agent-type key, which is not bound to a person, gets `400 invalid_agent_attribution` if it sends it. The stamp never changes a permission answer. See [Agent attribution](/developers/plan/conventions#agent-attribution). |

#### Error codes

| Status | When |
|--------|------|
| `400` | The agent name is invalid (`invalid_agent_attribution`). |
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `403` | Authenticated but not allowed: missing scope (`insufficient_scope`, which is also what an agent or organization key gets on an operation that needs a person, and what a personal key gets when its explicit Plan scopes do not cover the endpoint) or a guest account (`guest_not_allowed`). |
| `404` | Not found, or not visible to you. Both cases return the same body. |

#### Example (curl)

```bash
curl -sS -X DELETE "https://api.dailybot.com/v1/plan/tasks/ENG-142/attachments/00000000-0000-4000-8000-000000000009/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan task attachment delete ENG-142 00000000-0000-4000-8000-000000000009 --yes
```

#### Notes

- Scope: `tasks:write`.
- Rate limit: 60 writes per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### GET `/v1/plan/tasks/{task_id}/events/` · Beta

**A task's activity, rendered from the event log**

Events carry ids, enum members, numbers, booleans and dates — never user prose. There is no title, description, comment body or label name in a payload. Join what you are entitled to read: comment bodies come from the comments endpoint, titles from the task itself.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (read)
- **Rate limit:** `default`
- **Pagination:** Page-number pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |

#### Query parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `page` | integer | No | 1-based page number. |
| `page_size` | integer | No | Rows per page. Default 50, maximum 100. Out-of-range values are clamped, never rejected: asking for 500 returns 100. |
| `event_type` | array | No | Filter to one or more event types. |

#### TaskEvent object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `uuid` | string | Yes | Stable public identifier. |
| `event_type` | string | Yes | The event type. New types are added over time: ignore ones you do not recognise. |
| `entity` | object | No | — |
| `payload` | object | No | Ids, enum values, numbers, booleans and dates only, never user-written text. |
| `actor` | object | No | Who acted. |
| `executed_by_agent` | object | null | No | The agent that executed this on behalf of the person, or `null` when no agent was named: an object with `uuid`, `name`, `username` and `avatar`. The person in the author field is still the author; the agent is shown as the one who executed it. |
| `origin` | string | No | — |
| `correlation_id` | string | null | No | — |
| `observed_at` | string | No | When it was recorded. |
| `occurred_at` | string | Yes | When it happened. |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `count` | integer | Yes | Total number of rows. |
| `next` | uri | Yes | URL of the next page, or `null`. |
| `previous` | uri | Yes | URL of the previous page, or `null`. |
| `results` | array<TaskEvent> | Yes | The rows on this page. See [TaskEvent](#plan-task-events-list-taskevent). |

#### Error codes

| Status | When |
|--------|------|
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `404` | Not found, or not visible to you. Both cases return the same body. |

#### Example (curl)

```bash
curl -sS "https://api.dailybot.com/v1/plan/tasks/ENG-142/events/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan task events ENG-142 --json
```

##### Response

```bash
{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "uuid": "00000000-0000-4000-8000-00000000000f",
      "event_type": "task.moved",
      "entity": {},
      "payload": {},
      "actor": {},
      "origin": "web",
      "correlation_id": null,
      "observed_at": "example",
      "occurred_at": "example"
    }
  ]
}
```

#### Notes

- Scope: `tasks:read`.
- Rate limit: 120 reads per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### GET `/v1/plan/tasks/{task_id}/activity/` · Beta

**A task's activity feed, enriched for display**

Paginated, with the same row shape as `GET /v1/plan/activity/` (task card plus resolved `changes[{field, from, to}]`). This is what `?include=activity` embeds on task detail. For the raw event log use `GET …/tasks/{task_id}/events/`.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (read)
- **Rate limit:** `default`
- **Pagination:** Page-number pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |

#### Query parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `page` | integer | No | 1-based page number. |
| `page_size` | integer | No | Rows per page. Default 50, maximum 100. Out-of-range values are clamped, never rejected: asking for 500 returns 100. |

#### ActivityEvent object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `uuid` | string | Yes | Stable public identifier. |
| `type` | string | Yes | The event type. New types are added over time: ignore ones you do not recognise. |
| `actor` | object | Yes | Who acted. |
| `executed_by_agent` | object | null | No | The agent that executed this on behalf of the person, or `null` when no agent was named: an object with `uuid`, `name`, `username` and `avatar`. The person in the author field is still the author; the agent is shown as the one who executed it. |
| `created_at` | string | Yes | When the row was created. |
| `task` | object | No | Shape: `{uuid, key, title, board {uuid, key, name} | null} | null`. |
| `payload` | object | Yes | Ids, enum values, numbers, booleans and dates only, never user-written text. |
| `changes` | array | Yes | Resolved field changes, `[{field, from, to}]`. |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `count` | integer | Yes | Total number of rows. |
| `next` | uri | Yes | URL of the next page, or `null`. |
| `previous` | uri | Yes | URL of the previous page, or `null`. |
| `results` | array<ActivityEvent> | Yes | The rows on this page. See [ActivityEvent](#plan-task-activity-list-activityevent). |

#### Error codes

| Status | When |
|--------|------|
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `404` | Not found, or not visible to you. Both cases return the same body. |

#### Example (curl)

```bash
curl -sS "https://api.dailybot.com/v1/plan/tasks/ENG-142/activity/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan task activity ENG-142 --updated-since 2026-09-20T00:00:00Z
```

##### Response

```bash
{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "uuid": "00000000-0000-4000-8000-00000000000f",
      "type": "task.moved",
      "actor": {},
      "created_at": "example",
      "task": {},
      "payload": {},
      "changes": []
    }
  ]
}
```

#### Notes

- Scope: `tasks:read`.
- Rate limit: 120 reads per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### GET `/v1/plan/attachments/resolve/` · Beta

**Resolve attachment references**

Turns the attachment references you hold (for example the `attachment:{uuid}` markers in a description, or a stored `content_url`) into each attachment's current `url`. Pass 1 to 50 uuids in `ids`, separated by commas; it covers task, comment, project, goal, board, milestone and project-update attachments. An id that does not exist, that you cannot see, or whose attachment is not `ready` is simply absent from `resolved`: the three cases look the same and there is no error. Do not store `url` and do not paste it into public places: treat it as opaque. `url_expires_at` is either `null` or an ISO timestamp, so ask again when you render. To download, prefer `GET …/attachments/{attachment_id}/content/` with your credential.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (read)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Query parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `ids` | string | Yes | Attachment uuids, separated by commas. |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `resolved` | object | Yes | A map from each attachment uuid you can see to `{url, url_expires_at}`. Absent ids are not listed. |
| `resolved.{uuid}.url` | string | Yes | The attachment's current download link. |
| `resolved.{uuid}.url_expires_at` | string | null | Yes | When the link stops working, as an ISO datetime, or `null` when it has no expiry. |

#### Error codes

| Status | When |
|--------|------|
| `400` | `ids` is empty or holds a malformed uuid (`invalid_filter_value`, refused rather than skipped), or has more than 50 values (`too_many_filter_values`). |
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |

#### Example (curl)

```bash
curl -sS "https://api.dailybot.com/v1/plan/attachments/resolve/?ids=00000000-0000-4000-8000-000000000009,00000000-0000-4000-8000-000000000010" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN"
```

#### Scenario examples

##### CLI

```bash
dailybot plan tasks attachments-resolve 00000000-0000-4000-8000-000000000009
```

##### Response

```bash
{
  "resolved": {
    "00000000-0000-4000-8000-000000000009": {
      "url": "/v1/plan/tasks/00000000-0000-4000-8000-000000000003/attachments/00000000-0000-4000-8000-000000000009/content/",
      "url_expires_at": null
    }
  }
}
```

#### Notes

- Scope: `tasks:read`.
- Rate limit: 120 reads per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### PATCH `/v1/plan/tasks/{task_id}/comments/{comment_id}/attachments/{attachment_id}/` · Beta

**Rename a comment attachment**

Changes the display file name; the stored bytes do not change. Anyone who may write to the parent can rename its attachments.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |
| `comment_id` | string | Yes | The comment's uuid. |
| `attachment_id` | uuid | Yes | The attachment's uuid. |

#### Headers

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `X-Dailybot-Agent-Name` | string | No | The name of the agent that executed this write on the person's behalf. Use it on multipart and body-less writes (DELETE, archive, restore); on JSON writes send the body field `agent_name` instead, which wins if both are present. Percent-encode the value as UTF-8. Control characters are stripped; a blank value means no agent. More than 128 characters, or a value that cannot be decoded, is `400 invalid_agent_attribution` (never truncated). An agent-type key, which is not bound to a person, gets `400 invalid_agent_attribution` if it sends it. The stamp never changes a permission answer. See [Agent attribution](/developers/plan/conventions#agent-attribution). |

#### Request body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `filename` | string | Yes | The new file name (1–255 characters). The stored bytes do not change. |
| `agent_name` | string | No | The name of the agent that executed this write on the person's behalf (max 128 characters, blank means no agent). Takes priority over the `X-Dailybot-Agent-Name` header. See [Agent attribution](/developers/plan/conventions#agent-attribution). |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `(body)` | TaskAttachment | Yes | A [TaskAttachment](#plan-task-comments-list-taskattachment) object. |

#### Error codes

| Status | When |
|--------|------|
| `400` | Validation failed; the response `code` says which field. `invalid_agent_attribution` means the agent name is invalid. |
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `403` | You may not write here (`insufficient_scope`), or you are a guest (`guest_not_allowed`). |
| `404` | The parent or the attachment does not exist or you cannot see it (`not_found`), never a 403. |

#### Example (curl)

```bash
curl -sS -X PATCH "https://api.dailybot.com/v1/plan/tasks/ENG-142/comments/00000000-0000-4000-8000-000000000008/attachments/00000000-0000-4000-8000-000000000009/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "filename": "spec-v2.pdf"
}'
```

#### Scenario examples

##### CLI

```bash
dailybot plan task comment attachments rename ENG-142 00000000-0000-4000-8000-000000000008 00000000-0000-4000-8000-000000000009 spec-v2.pdf
```

#### Notes

- Scope: `tasks:write`.
- Rate limit: 60 writes per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

### GET `/v1/plan/tasks/{task_id}/comments/{comment_id}/reactions/` · Beta

**List who reacted to a comment**

Everyone who reacted, oldest first, as a page: the full list behind the capped `users` preview on each of the comment's reactions. `emoji` narrows to one emoji.

- **Auth:** API key (`X-API-KEY`), CLI Bearer (read)
- **Rate limit:** `default`
- **Pagination:** Page-number pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `task_id` | string | Yes | A task uuid **or** its key, such as `ENG-142`, including a key retired by a board rename. Resolution is scoped to your organization first, so another organization's key is a 404 identical to a missing one. Numeric ids are never accepted. |
| `comment_id` | string | Yes | The comment's uuid. |

#### Query parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `page` | integer | No | 1-based page number. |
| `page_size` | integer | No | Rows per page. Default 50, maximum 100. Out-of-range values are clamped, never rejected: asking for 500 returns 100. |
| `emoji` | string | No | One emoji; every emoji when omitted. The same rule as writes: anything else is `400 reaction_invalid_emoji`. |

#### Reactor object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `emoji` | string | Yes | — |
| `user` | ActorRef | Yes | Who reacted. |
| `executed_by_agent` | AgentRef | null | No | The agent that executed the reaction for that person, or `null`. |
| `created_at` | datetime | Yes | — |

#### ActorRef object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `kind` | string | Yes | — |
| `uuid` | string | Yes | Stable public identifier. |
| `name` | string | No | Display name. |
| `username` | string | null | No | — |
| `avatar_url` | string | null | No | — |
| `has_photo` | boolean | No | — |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `count` | integer | Yes | Total number of rows. |
| `next` | uri | Yes | URL of the next page, or `null`. |
| `previous` | uri | Yes | URL of the previous page, or `null`. |
| `results` | array<Reactor> | Yes | The page of [Reactor](#plan-task-comment-reactions-list-reactor) objects. |

#### Error codes

| Status | When |
|--------|------|
| `400` | `emoji` is not a single emoji (`reaction_invalid_emoji`), or a paging value is not valid. |
| `401` | Missing, expired or malformed credential (`credential_absent`, `credential_expired`, `credential_malformed`). |
| `402` | Plan is not enabled for your organization yet (`plan_upgrade_required`). Expected during the Beta: write to support@dailybot.com. |
| `404` | The task or the comment does not exist or you cannot see it (`not_found`), never a 403. |

#### Example (curl)

```bash
curl -sS "https://api.dailybot.com/v1/plan/tasks/ENG-142/comments/00000000-0000-4000-8000-000000000008/reactions/?emoji=%F0%9F%91%8D" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan task comment-reactions ENG-142 00000000-0000-4000-8000-000000000008
```

##### Response

```bash
{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "emoji": "👍",
      "user": {
        "kind": "user",
        "uuid": "00000000-0000-4000-8000-000000000001",
        "name": "Ana"
      },
      "executed_by_agent": null,
      "created_at": "2026-09-30T14:00:00Z"
    }
  ]
}
```

#### Notes

- Scope: `tasks:read`.
- Rate limit: 120 reads per minute per actor.
- Works with a login session, a CLI user token, a personal API key, or an agent or organization key. A personal key sees what its person sees; an agent or organization key acts as a system actor and sees organization-visible boards only.

---

## Developer portal navigation

**Getting Started**

- [Overview](/developers)
- [Quick start](/developers/getting-started)
- [Authentication](/developers/authentication)

**API Reference**

- [API Overview](/developers/api)
- [Users](/developers/api/users)
- [Organization](/developers/api/organization)
- [Teams](/developers/api/teams)
- [Invitations](/developers/api/invitations)
- [Check-ins](/developers/api/check-ins)
- [Forms](/developers/api/forms)
- [Labels](/developers/api/labels)
- [Report channels](/developers/api/report-channels)
- [Templates](/developers/api/templates)
- [Kudos](/developers/api/kudos)
- [Mood tracking](/developers/api/mood)
- [Important dates](/developers/api/important-dates)
- [Messaging](/developers/api/messaging)
- [Automations](/developers/api/workflows)
- [Webhooks](/developers/api/webhooks)
- [Commands platform](/developers/api/commands-platform)
- [Agents](/developers/api/agents)
- [OAuth2](/developers/api/oauth2)
- [Integrations](/developers/api/integrations)
- [CLI](/developers/api/cli)
- [Plan · Projects](/developers/api/plan-projects)
- [Plan · Goals](/developers/api/plan-goals)
- [Plan · Boards](/developers/api/plan-boards)
- [Plan · Tasks](/developers/api/plan-tasks)
- [Plan · Comments & files](/developers/api/plan-collaboration) (this page)
- [Plan · Home & search](/developers/api/plan-home)
- [Plan · Notifications & reports](/developers/api/plan-notifications)

**Dailybot Plan**

- [Overview](/developers/plan)
- [Concepts](/developers/plan/concepts)
- [Quickstart](/developers/plan/quickstart)
- [Authentication & scopes](/developers/plan/authentication)
- [Agents on Plan](/developers/plan/agents)
- [Conventions](/developers/plan/conventions)
- [Errors](/developers/plan/errors)
- [CLI for Plan](/developers/plan/cli)
- [Agent skill](/developers/plan/agent-skill)
- [Recipe: live board](/developers/plan/recipes/board-live-updates)
- [Recipe: home in one request](/developers/plan/recipes/home-in-one-request)
- [Recipe: bulk create](/developers/plan/recipes/bulk-create)
- [Recipe: move on PR merge](/developers/plan/recipes/move-on-pr-merge)
- [Recipe: goal progress](/developers/plan/recipes/goal-progress)
- [Recipe: webhooks](/developers/plan/recipes/webhooks)

**API guides**

- [Errors & Status Codes](/developers/errors)
- [Rate Limits](/developers/rate-limits)
- [Conventions](/developers/conventions)
- [API Changelog](/developers/api-changelog)
- [Recipes](/developers/recipes)

**Developer Features**

- [Custom commands](/developers/custom-commands)
- [Serverless commands](/developers/serverless)
- [Webhooks & events](/developers/webhooks)
- [Automation API trigger](/developers/workflow-trigger)
- [Activity API](/developers/activity-api)

**CLI**

- [Overview](/developers/cli)
- [Authentication](/developers/cli-authentication)
- [Command reference](/developers/cli-reference)
- [CI/CD recipes](/developers/cli-ci-cd)
- [Configuration](/developers/cli-configuration)
- [Troubleshooting](/developers/cli-troubleshooting)

**Agent Skill**

- [Overview](/developers/agent-skill)
- [Skills catalog](/skills)

---

## Site navigation

**Product:**
- [Home](/)
- [Product](/product)
- [Pricing](/pricing)
- [Enterprise](/enterprise)
- [Integrations](/integrations)
- [Templates](/templates)

**Resources:**
- [Blog](/blog)
- [Academy](/academy)
- [Changelog](/changelog)
- [Help Center](/help)
- [Developers](/developers)
- [Agents](/agents)

**Company:**
- [About](/about)
- [Careers](/careers)
- [Security](/security)
- [Contact Sales](/demo)

**Connect:**
- [LinkedIn](https://www.linkedin.com/company/dailybot/)
- [X/Twitter](https://twitter.com/dailybot)
- [GitHub](https://github.com/Dailybot-Inc)
- [YouTube](https://www.youtube.com/channel/UC3uM9V52vwX7e3vQpCc4qvA)

