# Plan · Goals

> Goals say what the work is for. They point at projects; nothing lives inside a goal. Part of the Dailybot Plan API (Beta).

Language: en
Canonical: https://www.dailybot.com/developers/api/plan-goals
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 · Goals**. 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

Goals say what the work is for. They point at projects; nothing lives inside a goal. Part of the Dailybot Plan API (Beta).

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/v1/plan/goals/` | List goals |
| POST | `/v1/plan/goals/` | Create a goal |
| GET | `/v1/plan/goals/{goal_id}/` | One goal, with its derived progress |
| PATCH | `/v1/plan/goals/{goal_id}/` | Update a goal, or declare its status |
| POST | `/v1/plan/goals/{goal_id}/archive/` | Archive a goal. The projects survive, unpointed |
| POST | `/v1/plan/goals/{goal_id}/restore/` | Bring an archived goal back |
| POST | `/v1/plan/goals/{goal_id}/projects/` | Link a project to a goal (from the goal page) |
| DELETE | `/v1/plan/goals/{goal_id}/projects/{project_id}/` | Unlink a project from a goal |
| GET | `/v1/plan/goals/{goal_id}/attachments/` | List a goal's attachments |
| POST | `/v1/plan/goals/{goal_id}/attachments/` | Upload an attachment to a goal |
| GET | `/v1/plan/goals/{goal_id}/attachments/{attachment_id}/content/` | Download a goal attachment's bytes |
| DELETE | `/v1/plan/goals/{goal_id}/attachments/{attachment_id}/` | Remove an attachment from a goal |
| PATCH | `/v1/plan/goals/{goal_id}/attachments/{attachment_id}/` | Rename a goal attachment |

### GET `/v1/plan/goals/` · Beta

**List goals**

The goals you can see, as a page. Filter by `status`, `owned_by`, a date inside the goal's period with `active_on`, or text with `search`. `include=progress,projects` adds the progress roll-up and linked projects.

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

#### Query parameters

##### Sorting & expansion

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `include` | string | No | Comma-separated roll-ups to embed: `progress`, `projects`. Absent by default because each is an aggregate. An unknown token is `400 invalid_filter_value`; an empty value is a no-op. |

##### Pagination

| 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. |

##### Filters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `search` | string | No | Matches title and key. Longer than 256 characters is `400 search_query_too_long`, not truncated. `q` is an alias. |
| `status` | string | No | Repeatable. Filters by declared status. |
| `owned_by` | string | No | The accountable person's uuid. Named `owned_by` rather than `owner` because the task grammar's `owner` accepts `me` and `unowned`, and one parameter name that means two different value spaces is how a client sends the wrong one. |
| `active_on` | string | No | Goals whose period covers this date - the roadmap's own question. |

##### Archived rows

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `include_archived` | boolean | No | Include archived rows alongside live ones. Distinct from `is_archived`, which selects one set or the other: `include_archived=true` is the union. Lists return live rows unless you opt in. |

#### Goal object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `uuid` | uuid | Yes | Stable public identifier. |
| `name` | string | Yes | Display name. Max 120 characters. |
| `description` | string | null | No | Free-form description. |
| `status` | enum | Yes | Current status. One of `not_started`, `on_track`, `at_risk`, `off_track`, `achieved`, `missed`. |
| `period_start` | date | Yes | First day of the goal's period. |
| `period_end` | date | Yes | Last day of the goal's period. |
| `owner` | UserRef | null | No | The person accountable for the task. See [UserRef](#plan-goals-list-userref). |
| `team` | TeamRef | null | No | The team. See [TeamRef](#plan-goals-list-teamref). |
| `progress` | GoalProgress | null | No | Progress roll-up over the tasks you can see. See [GoalProgress](#plan-goals-list-goalprogress). |
| `project_count` | integer | No | Number of linked projects. |
| `projects` | array | No | Linked projects. Items: `{uuid, name, slug, health, lead}`. |
| `is_archived` | boolean | Yes | Whether the row is archived. Archive is the delete: archived rows stay readable and restorable. |
| `completed_at` | date-time | null | No | When it was completed, or `null`. |
| `archived_at` | date-time | null | No | When the row was archived. |
| `created_at` | date-time | No | When the row was created. |
| `updated_at` | date-time | No | When the row last changed. |
| `viewer` | object | Yes | What you can do with this row. Shape: `{can_manage: boolean}`. |

#### UserRef object

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

#### TeamRef object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `uuid` | string | Yes | Stable public identifier. |
| `name` | string | No | Display name. |

#### GoalProgress object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `total` | integer | Yes | All tasks counted. |
| `completed` | integer | Yes | Tasks in a `done` or `canceled` state. |
| `open` | integer | No | Tasks in a `backlog`, `todo` or `in_progress` state. |
| `blocked` | integer | No | Tasks with a live blocker. |
| `overdue` | integer | No | Open tasks past their due date. |
| `percent_complete` | integer | Yes | `completed` as a percentage of `total`. |
| `is_partial` | boolean | Yes | `true` when some of the goal's work is hidden from you, so the numbers cover only what you can see. |

#### 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<Goal> | Yes | The rows on this page. See [Goal](#plan-goals-list-goal). |

#### 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. |
| `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`). |
| `429` | Rate limit reached. Wait the number of seconds in `Retry-After`. |

#### Example (curl)

```bash
curl -sS "https://api.dailybot.com/v1/plan/goals/?include=progress,projects" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan goal list --include progress --include projects
```

##### Response

```bash
{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "uuid": "00000000-0000-4000-8000-000000000006",
      "name": "Q4 Roadmap",
      "description": null,
      "status": "on_track",
      "period_start": "2026-09-28",
      "period_end": "2026-10-15",
      "owner": {
        "uuid": "00000000-0000-4000-8000-00000000000c",
        "name": "Ada L."
      },
      "team": null,
      "progress": {
        "total": 10,
        "completed": 4,
        "percent_complete": 40,
        "is_partial": false
      },
      "project_count": 1,
      "projects": [],
      "is_archived": false,
      "completed_at": null,
      "archived_at": null,
      "created_at": "2026-09-25T10:14:02Z",
      "updated_at": "2026-09-25T10:14:02Z",
      "viewer": {}
    }
  ]
}
```

#### 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/goals/` · Beta

**Create a goal**

Creates a goal with a period and a declared `status`. A live goal with the same name is `409 goal_name_conflict`. Every non-guest member can call it (with a login session or a personal API key); an agent or organization key cannot.

- **Auth:** CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### 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 |
|------|------|----------|-------------|
| `name` | string | Yes | Display name. Max 120 characters. |
| `description` | string | No | Free-form description. Max 2000 characters. |
| `period_start` | date | Yes | First day of the goal's period. |
| `period_end` | date | Yes | Last day of the goal's period. |
| `owner` | uuid | null | No | The owner's user uuid. The person must already be able to see the board (`400 participant_cannot_access_board` otherwise). |
| `team` | uuid | null | No | The team. |
| `status` | enum | No | Current status. One of `not_started`, `on_track`, `at_risk`, `off_track`, `achieved`, `missed`. |
| `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)` | Goal | Yes | A [Goal](#plan-goals-list-goal) 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. |
| `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`). |
| `409` | A live goal already has this name (`goal_name_conflict`). |
| `429` | Rate limit reached. Wait the number of seconds in `Retry-After`. |

#### Example (curl)

```bash
curl -sS -X POST "https://api.dailybot.com/v1/plan/goals/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Q4 Roadmap",
    "period_start": "2026-10-01",
    "period_end": "2026-12-31",
    "status": "on_track"
  }'
```

#### Scenario examples

##### CLI

```bash
dailybot plan goal create -n "Q4 Roadmap" --period-start 2026-10-01 --period-end 2026-12-31
```

#### Notes

- Scope: `tasks:admin` — container writes. A non-guest member can call it with a login session or a personal API key (a key with explicit Plan scopes needs `tasks:write`, which covers it); an agent or organization key gets `403 insufficient_scope`.
- Rate limit: 60 writes per minute per actor.
- Needs a person: call it with a login session, a CLI user token or a personal API key. An agent or organization key gets `403 insufficient_scope`.

### GET `/v1/plan/goals/{goal_id}/` · Beta

**One goal, with its derived progress**

Always returns `progress`, `projects` and `project_count`; the `include` parameter is not needed here.

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

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `goal_id` | string | Yes | The goal's uuid. |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `(body)` | Goal | Yes | A [Goal](#plan-goals-list-goal) object. |

#### 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. |
| `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. |
| `429` | Rate limit reached. Wait the number of seconds in `Retry-After`. |

#### Example (curl)

```bash
curl -sS "https://api.dailybot.com/v1/plan/goals/00000000-0000-4000-8000-000000000006/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan goal get 00000000-0000-4000-8000-000000000006
```

#### 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/goals/{goal_id}/` · Beta

**Update a goal, or declare its status**

Changes a goal's fields or declares its `status` (`on_track`, `at_risk`, …). Send only the fields you change. Every non-guest member can call it (with a login session or a personal API key); an agent or organization key cannot.

- **Auth:** CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `goal_id` | string | Yes | The goal'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 |
|------|------|----------|-------------|
| `name` | string | No | Display name. Max 120 characters. |
| `description` | string | No | Free-form description. Max 2000 characters. |
| `period_start` | date | No | First day of the goal's period. |
| `period_end` | date | No | Last day of the goal's period. |
| `owner` | uuid | null | No | The owner's user uuid. The person must already be able to see the board (`400 participant_cannot_access_board` otherwise). |
| `team` | uuid | null | No | The team. |
| `status` | enum | No | Current status. One of `not_started`, `on_track`, `at_risk`, `off_track`, `achieved`, `missed`. |
| `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)` | Goal | Yes | A [Goal](#plan-goals-list-goal) 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. |
| `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. |
| `409` | A live goal already has this name (`goal_name_conflict`). |
| `429` | Rate limit reached. Wait the number of seconds in `Retry-After`. |

#### Example (curl)

```bash
curl -sS -X PATCH "https://api.dailybot.com/v1/plan/goals/00000000-0000-4000-8000-000000000006/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "at_risk"
  }'
```

#### Scenario examples

##### CLI

```bash
dailybot plan goal update 00000000-0000-4000-8000-000000000006 --status at_risk
```

#### Notes

- Scope: `tasks:admin` — container writes. A non-guest member can call it with a login session or a personal API key (a key with explicit Plan scopes needs `tasks:write`, which covers it); an agent or organization key gets `403 insufficient_scope`.
- Rate limit: 60 writes per minute per actor.
- Needs a person: call it with a login session, a CLI user token or a personal API key. An agent or organization key gets `403 insufficient_scope`.

### POST `/v1/plan/goals/{goal_id}/archive/` · Beta

**Archive a goal. The projects survive, unpointed**

Archives the goal. Nothing lives inside a goal, so its projects stay where they are, no longer pointing at it. Send `?dry_run=true` first to see the consequence without archiving.

- **Auth:** CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `goal_id` | string | Yes | The goal's uuid. |

#### Query parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `dry_run` | boolean | No | Preview the consequence without performing it. The response has the same shape, `{operation, dry_run, reversible, restore_path, consequence, affects}`, but nothing is written and no event is emitted. Show `consequence` to a person before acting. |

#### 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). |

#### DryRunPreview object

What the call answers with `?dry_run=true`: the consequence, without performing it. Nothing is written and no event is emitted.


| Name | Type | Required | Description |
|------|------|----------|-------------|
| `operation` | string | Yes | The operation that would run. |
| `dry_run` | boolean | Yes | Always `true`. |
| `reversible` | boolean | Yes | Whether the operation can be undone. |
| `restore_path` | string | null | Yes | The path that would undo it, or `null` when there is none. |
| `consequence` | string | Yes | A sentence to show a person before acting. It states the cascade rather than summarising it. |
| `affects` | object | Yes | What the operation would touch, as counts (integers) by kind. |
| `would_refuse` | boolean | No | Workflow state archive only: `true` when the real call would be refused. |
| `refusal_code` | string | No | Workflow state archive only: the error code the real call would answer with. |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `(body)` | Goal | DryRunPreview | Yes | A [Goal](#plan-goals-list-goal) object. With `?dry_run=true`, a [DryRunPreview](#plan-goal-archive-dryrunpreview) object instead. |

#### 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. |
| `429` | Rate limit reached. Wait the number of seconds in `Retry-After`. |

#### Example (curl)

```bash
curl -sS -X POST "https://api.dailybot.com/v1/plan/goals/00000000-0000-4000-8000-000000000006/archive/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN"
```

#### Scenario examples

##### CLI

```bash
dailybot plan goal archive 00000000-0000-4000-8000-000000000006 --dry-run
```

#### Notes

- Scope: `tasks:admin` — container writes. A non-guest member can call it with a login session or a personal API key (a key with explicit Plan scopes needs `tasks:write`, which covers it); an agent or organization key gets `403 insufficient_scope`.
- Rate limit: 60 writes per minute per actor.
- Needs a person: call it with a login session, a CLI user token or a personal API key. An agent or organization key gets `403 insufficient_scope`.

### POST `/v1/plan/goals/{goal_id}/restore/` · Beta

**Bring an archived goal back**

The inverse of `archive/`, mirroring `boards/{board_id}/restore/`. Restoring a goal that is already live is a `200` no-op, not an error. Goal names are unique among LIVE goals, so if the name was taken while this one was archived the restore answers `409 goal_name_conflict` — the one edge that separates a real restore from a flag flip.

- **Auth:** CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `goal_id` | string | Yes | The goal'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)` | Goal | Yes | A [Goal](#plan-goals-list-goal) 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. |
| `409` | A live goal already has this name (`goal_name_conflict`). |

#### Example (curl)

```bash
curl -sS -X POST "https://api.dailybot.com/v1/plan/goals/00000000-0000-4000-8000-000000000006/restore/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN"
```

#### Scenario examples

##### CLI

```bash
dailybot plan goal restore 00000000-0000-4000-8000-000000000006
```

#### Notes

- Scope: `tasks:admin` — container writes. A non-guest member can call it with a login session or a personal API key (a key with explicit Plan scopes needs `tasks:write`, which covers it); an agent or organization key gets `403 insufficient_scope`.
- Rate limit: 60 writes per minute per actor.
- Needs a person: call it with a login session, a CLI user token or a personal API key. An agent or organization key gets `403 insufficient_scope`.

### POST `/v1/plan/goals/{goal_id}/projects/` · Beta

**Link a project to a goal (from the goal page)**

Links a project to the goal, from the goal's side. A project can serve several goals. The response is the goal with its `projects`.

- **Auth:** CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `goal_id` | string | Yes | The goal'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 |
|------|------|----------|-------------|
| `project` | uuid | Yes | The project. |
| `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)` | Goal | Yes | A [Goal](#plan-goals-list-goal) 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/goals/00000000-0000-4000-8000-000000000006/projects/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "project": "00000000-0000-4000-8000-000000000001"
  }'
```

#### Scenario examples

##### CLI

```bash
dailybot plan goal link 00000000-0000-4000-8000-000000000006 00000000-0000-4000-8000-000000000001
```

#### Notes

- Scope: `tasks:admin` — container writes. A non-guest member can call it with a login session or a personal API key (a key with explicit Plan scopes needs `tasks:write`, which covers it); an agent or organization key gets `403 insufficient_scope`.
- Rate limit: 60 writes per minute per actor.
- Needs a person: call it with a login session, a CLI user token or a personal API key. An agent or organization key gets `403 insufficient_scope`.

### DELETE `/v1/plan/goals/{goal_id}/projects/{project_id}/` · Beta

**Unlink a project from a goal**

Unlinks a project from the goal. The project itself is untouched.

- **Auth:** CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `goal_id` | string | Yes | The goal's uuid. |
| `project_id` | string | Yes | The project'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. |
| `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/goals/00000000-0000-4000-8000-000000000006/projects/00000000-0000-4000-8000-000000000001/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN"
```

#### Scenario examples

##### CLI

```bash
dailybot plan goal unlink 00000000-0000-4000-8000-000000000006 00000000-0000-4000-8000-000000000001 --yes
```

#### Notes

- Scope: `tasks:admin` — container writes. A non-guest member can call it with a login session or a personal API key (a key with explicit Plan scopes needs `tasks:write`, which covers it); an agent or organization key gets `403 insufficient_scope`.
- Rate limit: 60 writes per minute per actor.
- Needs a person: call it with a login session, a CLI user token or a personal API key. An agent or organization key gets `403 insufficient_scope`.

### GET `/v1/plan/goals/{goal_id}/attachments/` · Beta

**List a goal's attachments**

The goal's attachments, ordered by position. Anyone who can see the goal can list its attachments; a goal you cannot see is `404`. Each `url` is a download link. Do not store it: keep the attachment `uuid` and read it again when you need the file. To show an image in the goal's description, reference it as `attachment:{uuid}` and resolve it when you render, using the fresh `url` from this list.

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

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `goal_id` | string | Yes | The goal'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. |

#### 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-goal-attachments-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. |

#### 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<TaskAttachment> | Yes | The rows on this page. See [TaskAttachment](#plan-goal-attachments-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 goal 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/goals/00000000-0000-4000-8000-000000000006/attachments/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan goal attachments 00000000-0000-4000-8000-000000000006 --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/goals/{goal_id}/attachments/` · Beta

**Upload an attachment to a goal**

Attach a file to a goal. 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 goal holds at most 50 attachments (`attachment_limit_reached`).

- **Auth:** CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `goal_id` | string | Yes | The goal'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-goal-attachments-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` | Not a non-guest member acting with a login session or a personal API key (`insufficient_scope`); an agent or organization key always gets this. |
| `404` | The goal 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/goals/00000000-0000-4000-8000-000000000006/attachments/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN" \
  -F "file=@./screenshot.png" \
  -F "caption=Staging dashboard"
```

#### Scenario examples

##### CLI

```bash
dailybot plan goal attach 00000000-0000-4000-8000-000000000006 ./okr-brief.pdf --caption "OKR brief"
```

#### Notes

- Scope: `tasks:admin` — container writes. A non-guest member can call it with a login session or a personal API key (a key with explicit Plan scopes needs `tasks:write`, which covers it); an agent or organization key gets `403 insufficient_scope`.
- Rate limit: 60 writes per minute per actor.
- Needs a person: call it with a login session, a CLI user token or a personal API key. An agent or organization key gets `403 insufficient_scope`.

### GET `/v1/plan/goals/{goal_id}/attachments/{attachment_id}/content/` · Beta

**Download a goal 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. Anyone who can see the goal can download it.

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

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `goal_id` | string | Yes | The goal'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 goal 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/goals/00000000-0000-4000-8000-000000000006/attachments/00000000-0000-4000-8000-000000000009/content/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan goal attachment get 00000000-0000-4000-8000-000000000006 00000000-0000-4000-8000-000000000009 -o ./okr-brief.pdf
```

#### 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/goals/{goal_id}/attachments/{attachment_id}/` · Beta

**Remove an attachment from a goal**

Removes the attachment from the goal.

- **Auth:** CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `goal_id` | string | Yes | The goal'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` | Not a non-guest member acting with a login session or a personal API key (`insufficient_scope`); an agent or organization key always gets this. |
| `404` | The goal 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/goals/00000000-0000-4000-8000-000000000006/attachments/00000000-0000-4000-8000-000000000009/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN"
```

#### Scenario examples

##### CLI

```bash
dailybot plan goal attachment delete 00000000-0000-4000-8000-000000000006 00000000-0000-4000-8000-000000000009 --yes
```

#### Notes

- Scope: `tasks:admin` — container writes. A non-guest member can call it with a login session or a personal API key (a key with explicit Plan scopes needs `tasks:write`, which covers it); an agent or organization key gets `403 insufficient_scope`.
- Rate limit: 60 writes per minute per actor.
- Needs a person: call it with a login session, a CLI user token or a personal API key. An agent or organization key gets `403 insufficient_scope`.

### PATCH `/v1/plan/goals/{goal_id}/attachments/{attachment_id}/` · Beta

**Rename a goal attachment**

Changes the display file name; the stored bytes do not change. The rules are the container's own: organization administrators only.

- **Auth:** CLI Bearer (write)
- **Rate limit:** `default`
- **Pagination:** No pagination

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `goal_id` | string | Yes | The goal'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-goal-attachments-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 are not an organization administrator (`insufficient_scope`), or you are a guest (`guest_not_allowed`). An agent or organization key is refused here too. |
| `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/goals/00000000-0000-4000-8000-000000000006/attachments/00000000-0000-4000-8000-000000000009/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "filename": "spec-v2.pdf"
}'
```

#### Scenario examples

##### CLI

```bash
dailybot plan goal attachments rename 00000000-0000-4000-8000-000000000006 00000000-0000-4000-8000-000000000009 spec-v2.pdf
```

#### Notes

- Scope: `tasks:admin` — container writes. A non-guest member can call it with a login session or a personal API key (a key with explicit Plan scopes needs `tasks:write`, which covers it); an agent or organization key gets `403 insufficient_scope`.
- Rate limit: 60 writes per minute per actor.
- Needs a person: call it with a login session, a CLI user token or a personal API key. An agent or organization key gets `403 insufficient_scope`.

---

## 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) (this page)
- [Plan · Boards](/developers/api/plan-boards)
- [Plan · Tasks](/developers/api/plan-tasks)
- [Plan · Comments & files](/developers/api/plan-collaboration)
- [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)

