# Plan · Notifications & reports

> The notification catalogue, each person's switches and daily briefing, the organization's channel routes and scheduled reports, and the channels they post to. Part of the Dailybot Plan API (Beta).

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

---

> **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 · Notifications & reports**. 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.

Personal doors (`me/notifications`, `me/briefing`) need a person: a login session, a CLI user token or a personal API key; an agent or organization key gets `400 actor_required`. Routes, scheduled reports and their send-test are for organization administrators. Every send-test takes `?dry_run=true`, which renders and resolves without sending. A person's briefing always arrives by direct message and/or email, never in a channel.

## Endpoints in this group

The notification catalogue, each person's switches and daily briefing, the organization's channel routes and scheduled reports, and the channels they post to. Part of the Dailybot Plan API (Beta).

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/v1/plan/notifications/catalog/` | The notification catalogue |
| GET | `/v1/plan/me/notifications/` | My notification switches |
| PUT | `/v1/plan/me/notifications/` | Change my notification switches |
| GET | `/v1/plan/notification-routes/` | List the organization's channel routes |
| POST | `/v1/plan/notification-routes/` | Create a channel route |
| GET | `/v1/plan/notification-routes/{route_id}/` | Retrieve a channel route |
| PATCH | `/v1/plan/notification-routes/{route_id}/` | Change a channel route |
| DELETE | `/v1/plan/notification-routes/{route_id}/` | Delete a channel route |
| POST | `/v1/plan/notification-routes/{route_id}/send-test/` | Post a test message to a route's channel, or preview it |
| GET | `/v1/plan/notification-routes/{route_id}/deliveries/` | A route's last deliveries |
| GET | `/v1/plan/channels/` | Search the chat channels routes and reports can post to |
| GET | `/v1/plan/reports/` | List the organization's scheduled reports |
| POST | `/v1/plan/reports/` | Schedule a report |
| GET | `/v1/plan/reports/{report_id}/` | Retrieve a scheduled report |
| PATCH | `/v1/plan/reports/{report_id}/` | Change a scheduled report |
| DELETE | `/v1/plan/reports/{report_id}/` | Delete a scheduled report |
| GET | `/v1/plan/reports/{report_id}/preview/` | Preview a scheduled report with real data |
| POST | `/v1/plan/reports/{report_id}/send-test/` | Send a scheduled report now as a test, or preview what would be sent |
| GET | `/v1/plan/reports/{report_id}/runs/` | A scheduled report's last runs |
| GET | `/v1/plan/me/briefing/` | My daily briefing settings |
| PUT | `/v1/plan/me/briefing/` | Change my daily briefing |
| GET | `/v1/plan/me/briefing/preview/` | Preview today's briefing |
| POST | `/v1/plan/me/briefing/send-test/` | Send today's briefing to me now, or preview it |

### GET `/v1/plan/notifications/catalog/` · Beta

**The notification catalogue**

Every notification kind, personal and organization: the one catalogue the web settings, the CLI and the agent skill render from. `scope` is `personal` (a switch a person sets for themselves, by DM and/or email) or `org` (a kind a channel route can post). `key` values are stable lowercase identifiers; `default` is what a person gets before touching the switch; `immediate` kinds are never held by the burst window.

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

#### NotificationKind object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `key` | string | Yes | Stable lowercase identifier: what `items[].kind` and a route's `kinds` take. |
| `scope` | enum | Yes | `personal` (a switch a person sets for themselves, DM and/or email) or `org` (a kind a route can post to a channel). |
| `group` | string | Yes | The `groups[].key` it belongs to, for rendering. |
| `title` | string | Yes | — |
| `description` | string | Yes | — |
| `events` | array<string> | Yes | The task event types that produce it. |
| `targeting` | enum | Yes | Who it reaches: `me`, `watched`, `content_author`, `project_members`, `scheduled` or `org`. |
| `supports` | array<string> | Yes | The channels it can use: `chat`, `email`. |
| `default` | object | Yes | `{chat, email}`: what a person gets before touching the switch. |
| `immediate` | boolean | Yes | An immediate kind is never held by the burst window. |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `groups` | array<object> | Yes | `{key, title}` rows, in display order. |
| `kinds` | array<NotificationKind> | Yes | The [NotificationKind](#plan-notifications-catalog-notificationkind) objects. |

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

#### Example (curl)

```bash
curl -sS "https://api.dailybot.com/v1/plan/notifications/catalog/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan tasks notifications catalog
```

##### Response

```bash
{
  "groups": [
    {
      "key": "my_work",
      "title": "My work"
    }
  ],
  "kinds": [
    {
      "key": "task_assigned",
      "scope": "personal",
      "group": "my_work",
      "title": "Assigned to me",
      "description": "Someone made me the owner of a task.",
      "events": [
        "task.owner_changed"
      ],
      "targeting": "me",
      "supports": [
        "chat",
        "email"
      ],
      "default": {
        "chat": true,
        "email": false
      },
      "immediate": true
    }
  ]
}
```

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

**My notification switches**

The caller's effective switches, one item per personal kind, with `chat` / `email` values: the stored switch when there is one (`stored: true`), otherwise the catalogue default (`stored: false`). `destination` says where chat notifications go: a direct message by default, or a public channel the person chose. A person is never notified about their own actions, whatever these say.

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

#### NotificationDestination object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `type` | enum | Yes | `dm` (the default) or `channel`. |
| `channel` | ChatChannel | null | Yes | The public channel when `type` is `channel`. See [ChatChannel](#plan-me-notifications-get-chatchannel). |

#### ChatChannel object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `external_id` | string | Yes | The platform's channel id: the same value `dailybot chat send --channel` takes. |
| `name` | string | Yes | Channel name. |
| `type` | enum | Yes | One of `channel` (public), `private_channel`, `group_chat`. |

#### NotificationPreferenceItem object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `kind` | string | Yes | The catalogue `key`. |
| `group` | string | Yes | — |
| `title` | string | Yes | — |
| `supports` | array<string> | Yes | `chat`, `email`. |
| `default` | object | Yes | `{chat, email}` from the catalogue. |
| `stored` | boolean | Yes | `true` when the person set this switch; `false` when the value is the catalogue default. |
| `chat` | boolean | Yes | Effective value. |
| `email` | boolean | Yes | Effective value. |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `destination` | NotificationDestination | Yes | A [NotificationDestination](#plan-me-notifications-get-notificationdestination) object. |
| `items` | array<NotificationPreferenceItem> | Yes | One row per personal kind: [NotificationPreferenceItem](#plan-me-notifications-get-notificationpreferenceitem) objects. |
| `paused_until` | datetime | null | Yes | Reserved; always `null` in this version. |

#### Error codes

| Status | When |
|--------|------|
| `400` | The credential is an agent or organization key (`actor_required`); this endpoint needs a person. |
| `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` | Guest accounts cannot use Plan (`guest_not_allowed`). |

#### Example (curl)

```bash
curl -sS "https://api.dailybot.com/v1/plan/me/notifications/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN"
```

#### Scenario examples

##### CLI

```bash
dailybot plan tasks notifications get --me
```

##### Response

```bash
{
  "destination": {
    "type": "dm",
    "channel": null
  },
  "items": [
    {
      "kind": "task_assigned",
      "group": "my_work",
      "title": "Assigned to me",
      "supports": [
        "chat",
        "email"
      ],
      "default": {
        "chat": true,
        "email": false
      },
      "stored": true,
      "chat": true,
      "email": true
    }
  ],
  "paused_until": null
}
```

#### Notes

- Scope: `tasks:read`.
- Rate limit: 120 reads per minute per actor.
- Needs a person: call it with a login session, a CLI user token or a personal API key, which acts as its person. An agent or organization key gets `400 actor_required`.

### PUT `/v1/plan/me/notifications/` · Beta

**Change my notification switches**

Partial: only the kinds and channels you name are written; everything else keeps its effective value. Answers the full effective body, the same as `GET`. An unknown kind is `400 unknown_notification_kind` and an unknown field is `400 unknown_field` (`extra.parameter` names it). A `destination` channel must be public (`type: channel` on `GET /v1/plan/channels/`); a private one is `400 channel_not_found`, and notifications about members-only work still come by DM. `paused_until` is reserved: sending a value is `501 not_implemented`.

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

#### 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 |
|------|------|----------|-------------|
| `destination` | object | No | `{type: "dm"}` or `{type: "channel", channel: {external_id}}`. |
| `items` | array<object> | No | `{kind, chat?, email?}` rows: the catalogue `key` and the channels to set. Omit a channel to leave it as is. |
| `paused_until` | datetime | null | No | Reserved. Only `null` is accepted; a datetime is `501 not_implemented`. |
| `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 |
|------|------|----------|-------------|
| `destination` | NotificationDestination | Yes | A [NotificationDestination](#plan-me-notifications-get-notificationdestination) object. |
| `items` | array<NotificationPreferenceItem> | Yes | One row per personal kind: [NotificationPreferenceItem](#plan-me-notifications-get-notificationpreferenceitem) objects. |
| `paused_until` | datetime | null | Yes | Reserved; always `null` in this version. |

#### Error codes

| Status | When |
|--------|------|
| `400` | An unknown kind (`unknown_notification_kind`), an unknown field (`unknown_field`), a channel that is not public or not known (`channel_not_found`), an agent or organization key (`actor_required`), or an invalid agent name (`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` | Guest accounts cannot use Plan (`guest_not_allowed`). |

#### Example (curl)

```bash
curl -sS -X PUT "https://api.dailybot.com/v1/plan/me/notifications/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "items": [
    {
      "kind": "task_assigned",
      "email": true
    },
    {
      "kind": "comment_added",
      "chat": false
    }
  ]
}'
```

#### Scenario examples

##### CLI

```bash
dailybot plan tasks notifications set --me task_assigned --email on
```

#### Notes

- Scope: `tasks:write`.
- 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, which acts as its person. An agent or organization key gets `400 actor_required`.

### GET `/v1/plan/notification-routes/` · Beta

**List the organization's channel routes**

Every route: a chat channel, the organization notification kinds it receives, and its scope (the whole workspace, some boards or some projects). `viewer.can_manage` says whether the caller may create or change routes. Any member, and any key, may read.

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

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

#### NotificationRoute object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `uuid` | uuid | Yes | Stable public identifier. |
| `name` | string | Yes | Route name. |
| `enabled` | boolean | Yes | A disabled route keeps its settings and posts nothing. |
| `channel` | ChatChannel | Yes | Where it posts. See [ChatChannel](#plan-me-notifications-get-chatchannel). |
| `kinds` | array<string> | Yes | The organization notification kinds it receives (`key` values from the catalogue). |
| `scope` | RouteScope | Yes | Which work it covers. See [RouteScope](#plan-notification-routes-list-routescope). |
| `created_by` | UserRef | null | Yes | Who created it. See [UserRef](#plan-notification-routes-list-userref). |
| `created_at` | datetime | null | Yes | — |
| `updated_at` | datetime | null | Yes | — |

#### RouteScope object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `type` | enum | Yes | `all` (the whole workspace), `boards` or `projects`. |
| `uuids` | array<uuid> | Yes | The board or project uuids when `type` is not `all`. Only boards and projects the whole workspace can see are accepted. |

#### RoutesViewer object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `can_manage` | boolean | Yes | Whether the caller may create, change or delete routes and report schedules: an organization administrator with a credential that may write. |

#### 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 | — |

#### 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<NotificationRoute> | Yes | The page of [NotificationRoute](#plan-notification-routes-list-notificationroute) objects. |
| `viewer` | RoutesViewer | Yes | A [RoutesViewer](#plan-notification-routes-list-routesviewer) 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. |

#### Example (curl)

```bash
curl -sS "https://api.dailybot.com/v1/plan/notification-routes/" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan tasks routes list
```

##### Response

```bash
{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "uuid": "00000000-0000-4000-8000-000000000021",
      "name": "Engineering channel",
      "enabled": true,
      "channel": {
        "external_id": "C0123ABC",
        "name": "engineering",
        "type": "channel"
      },
      "kinds": [
        "task_completed",
        "project_update_posted",
        "project_lead_changed"
      ],
      "scope": {
        "type": "boards",
        "uuids": [
          "00000000-0000-4000-8000-000000000002"
        ]
      },
      "created_by": {
        "uuid": "00000000-0000-4000-8000-000000000001",
        "name": "Ana"
      },
      "created_at": "2026-09-30T14:00:00Z",
      "updated_at": "2026-09-30T14:00:00Z"
    }
  ],
  "viewer": {
    "can_manage": true
  }
}
```

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

**Create a channel route**

Organization administrators only. A route posts the organization notification kinds you pick (a task completed, a project update, a lead change…) to one chat channel, for the whole workspace or for some boards or projects. At most 10 routes per organization. Accepts `Idempotency-Key`.

- **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 | No | Route name. |
| `enabled` | boolean | No | Default `true`. |
| `channel` | object | No | `{external_id}`: the platform channel id, as `GET /v1/plan/channels/` lists it. Unknown ids are `400 channel_not_found`. |
| `kinds` | array<string> | No | Organization kinds from the catalogue (`scope: org`). Anything else is `400 unknown_notification_kind`. |
| `scope` | RouteScope | No | `{type, uuids}`. A members-only board or project is `400 route_scope_not_org_visible` with `extra.uuids`: channels only ever receive what the whole workspace can see. |
| `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)` | NotificationRoute | Yes | A [NotificationRoute](#plan-notification-routes-list-notificationroute) object. |

#### Error codes

| Status | When |
|--------|------|
| `400` | A field failed validation: `channel_not_found`, `unknown_notification_kind`, `route_scope_not_org_visible` (`extra.uuids`), `unknown_field`, or `notification_routes_limit_reached` (`extra.limit`, 10 routes). `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. |

#### Example (curl)

```bash
curl -sS -X POST "https://api.dailybot.com/v1/plan/notification-routes/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Engineering channel",
  "channel": {
    "external_id": "C0123ABC"
  },
  "kinds": [
    "task_completed",
    "project_update_posted",
    "project_lead_changed"
  ],
  "scope": {
    "type": "boards",
    "uuids": [
      "00000000-0000-4000-8000-000000000002"
    ]
  }
}'
```

#### Scenario examples

##### CLI

```bash
dailybot plan tasks routes create --name "Engineering channel" --channel C0123ABC --kind task_completed --kind project_update_posted --board 00000000-0000-4000-8000-000000000002
```

#### 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.
- Organization administrators only, with a login session, a CLI user token or a personal API key. Any member and any key may read.

### GET `/v1/plan/notification-routes/{route_id}/` · Beta

**Retrieve a channel route**

One route. A route in another organization is `404`.

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

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `route_id` | uuid | Yes | The route's uuid. |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `(body)` | NotificationRoute | Yes | A [NotificationRoute](#plan-notification-routes-list-notificationroute) 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. |
| `404` | The route does not exist in your organization (`not_found`), never a 403. |

#### Example (curl)

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

#### Scenario examples

##### CLI

```bash
dailybot plan tasks routes get 00000000-0000-4000-8000-000000000021
```

##### Response

```bash
{
  "uuid": "00000000-0000-4000-8000-000000000021",
  "name": "Engineering channel",
  "enabled": true,
  "channel": {
    "external_id": "C0123ABC",
    "name": "engineering",
    "type": "channel"
  },
  "kinds": [
    "task_completed",
    "project_update_posted",
    "project_lead_changed"
  ],
  "scope": {
    "type": "boards",
    "uuids": [
      "00000000-0000-4000-8000-000000000002"
    ]
  },
  "created_by": {
    "uuid": "00000000-0000-4000-8000-000000000001",
    "name": "Ana"
  },
  "created_at": "2026-09-30T14:00:00Z",
  "updated_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.

### PATCH `/v1/plan/notification-routes/{route_id}/` · Beta

**Change a channel route**

Organization administrators only. Partial: only the fields you send are written, with the same validation as create.

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

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `route_id` | uuid | Yes | The route'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 | Route name. |
| `enabled` | boolean | No | Default `true`. |
| `channel` | object | No | `{external_id}`: the platform channel id, as `GET /v1/plan/channels/` lists it. Unknown ids are `400 channel_not_found`. |
| `kinds` | array<string> | No | Organization kinds from the catalogue (`scope: org`). Anything else is `400 unknown_notification_kind`. |
| `scope` | RouteScope | No | `{type, uuids}`. A members-only board or project is `400 route_scope_not_org_visible` with `extra.uuids`: channels only ever receive what the whole workspace can see. |
| `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)` | NotificationRoute | Yes | A [NotificationRoute](#plan-notification-routes-list-notificationroute) object. |

#### Error codes

| Status | When |
|--------|------|
| `400` | A field failed validation: `channel_not_found`, `unknown_notification_kind`, `route_scope_not_org_visible` (`extra.uuids`), `unknown_field`, or `notification_routes_limit_reached` (`extra.limit`, 10 routes). `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 route does not exist in your organization (`not_found`), never a 403. |

#### Example (curl)

```bash
curl -sS -X PATCH "https://api.dailybot.com/v1/plan/notification-routes/00000000-0000-4000-8000-000000000021/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "enabled": false
}'
```

#### Scenario examples

##### CLI

```bash
dailybot plan tasks routes update 00000000-0000-4000-8000-000000000021 --disable
```

#### 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.
- Organization administrators only, with a login session, a CLI user token or a personal API key. Any member and any key may read.

### DELETE `/v1/plan/notification-routes/{route_id}/` · Beta

**Delete a channel route**

Organization administrators only. The channel stops receiving at once. Answers `204`.

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

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `route_id` | uuid | Yes | The route'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` | 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 route does not exist in your organization (`not_found`), never a 403. |

#### Example (curl)

```bash
curl -sS -X DELETE "https://api.dailybot.com/v1/plan/notification-routes/00000000-0000-4000-8000-000000000021/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN"
```

#### Scenario examples

##### CLI

```bash
dailybot plan tasks routes delete 00000000-0000-4000-8000-000000000021
```

#### 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.
- Organization administrators only, with a login session, a CLI user token or a personal API key. Any member and any key may read.

### POST `/v1/plan/notification-routes/{route_id}/send-test/` · Beta

**Post a test message to a route's channel, or preview it**

Organization administrators only. With `?dry_run=true` the sample is rendered and the channel resolved, and nothing is sent or logged. Without it, one message is posted and logged like any route post.

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

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `route_id` | uuid | Yes | The route's uuid. |

#### Query parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `dry_run` | boolean | No | `true` renders and resolves only; nothing is sent or logged. Fails closed: any value other than `0`, `false`, `no` or `off` is a dry run. |

#### 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 |
|------|------|----------|-------------|
| `dry_run` | boolean | Yes | Echoes the request: `true` when nothing was sent. |
| `channel` | ChatChannel | Yes | A [ChatChannel](#plan-me-notifications-get-chatchannel) object. |
| `text` | string | Yes | The rendered sample message. |
| `sent` | boolean | Yes | `false` on a dry run. |
| `status` | string | No | The delivery status when sent. |
| `delivery_uuid` | uuid | null | No | The delivery record when sent; see the deliveries endpoint. |

#### 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 route does not exist in your organization (`not_found`), never a 403. |

#### Example (curl)

```bash
curl -sS -X POST "https://api.dailybot.com/v1/plan/notification-routes/00000000-0000-4000-8000-000000000021/send-test/?dry_run=true" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN"
```

#### Scenario examples

##### CLI

```bash
dailybot plan tasks routes send-test 00000000-0000-4000-8000-000000000021 --dry-run
```

##### Response

```bash
{
  "dry_run": true,
  "channel": {
    "external_id": "C0123ABC",
    "name": "engineering",
    "type": "channel"
  },
  "text": "Test message from Dailybot Plan for the route \"Engineering channel\".",
  "sent": false
}
```

#### 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.
- Organization administrators only, with a login session, a CLI user token or a personal API key. Any member and any key may read.

### GET `/v1/plan/notification-routes/{route_id}/deliveries/` · Beta

**A route's last deliveries**

The newest 20 delivery rows, newest first: `sent`, `failed` (with a reason code) or `skipped` (`not_org_visible`, `rate_limited`). Never message text.

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

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `route_id` | uuid | Yes | The route's uuid. |

#### DeliveryRecord object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `uuid` | uuid | Yes | — |
| `status` | enum | Yes | `sent`, `failed` (see `error`) or `skipped` (`not_org_visible`, `rate_limited`). |
| `channel` | enum | Yes | `chat` or `email`. |
| `error` | string | null | Yes | A reason code when the delivery failed or was skipped. Never message text. |
| `message_id` | string | null | Yes | The platform's message id when it was posted. |
| `created_at` | datetime | Yes | — |

#### 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<DeliveryRecord> | Yes | The [DeliveryRecord](#plan-notification-route-deliveries-deliveryrecord) objects. |

#### 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 route does not exist in your organization (`not_found`), never a 403. |

#### Example (curl)

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

#### Scenario examples

##### CLI

```bash
dailybot plan tasks routes deliveries 00000000-0000-4000-8000-000000000021
```

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

**Search the chat channels routes and reports can post to**

The connected platform's channels, sorted by name, as a page. `search` is a case-insensitive substring of the name. `platform` names the platform (`slack`, `msteams`, `discord`, `google_chat`); with no chat platform connected the answer is `400 platform_not_connected`. Organization administrators see private channels the bot is in; everyone else sees public channels only (a private channel is absent, not forbidden). `type=channel` answers public channels only, for everyone: what a personal notification destination must be.

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

#### Query parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `search` | string | No | Case-insensitive substring of the channel name. |
| `type` | string | No | `channel` answers public channels only, for everyone. Without it, organization administrators also see private channels the bot is in. |
| `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<ChatChannel> | Yes | The page of [ChatChannel](#plan-me-notifications-get-chatchannel) objects. |
| `platform` | string | Yes | `slack`, `msteams`, `discord` or `google_chat`. |

#### Error codes

| Status | When |
|--------|------|
| `400` | No chat platform is connected (`platform_not_connected`), or `type` 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. |

#### Example (curl)

```bash
curl -sS "https://api.dailybot.com/v1/plan/channels/?search=eng&type=channel" \
  -H "X-API-KEY: $DAILYBOT_API_KEY"
```

#### Scenario examples

##### CLI

```bash
dailybot plan tasks channels search eng --type channel
```

##### Response

```bash
{
  "count": 1,
  "next": null,
  "previous": null,
  "platform": "slack",
  "results": [
    {
      "external_id": "C0123ABC",
      "name": "engineering",
      "type": "channel"
    }
  ]
}
```

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

**List the organization's scheduled reports**

Every schedule with its kind (`daily`, `week_start`, `week_end`), ISO `weekdays` (Monday = 1), local `time` in its IANA `timezone`, channel, email recipients, scope and last run. `viewer.can_manage` says whether the caller may change them (an organization administrator).

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

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

#### ReportSchedule object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `uuid` | uuid | Yes | — |
| `name` | string | Yes | — |
| `kind` | enum | Yes | `daily`, `week_start` or `week_end`. |
| `enabled` | boolean | Yes | — |
| `weekdays` | array<integer> | Yes | ISO weekdays, Monday = 1. A `week_start` or `week_end` report has exactly one. |
| `time` | string | Yes | `HH:MM`, 24-hour, in `timezone`. |
| `timezone` | string | Yes | IANA name. |
| `channel` | ChatChannel | null | Yes | Where it posts, or `null` for email only. See [ChatChannel](#plan-me-notifications-get-chatchannel). |
| `email_recipients` | array<UserRef> | Yes | See [UserRef](#plan-notification-routes-list-userref). |
| `scope` | RouteScope | Yes | See [RouteScope](#plan-notification-routes-list-routescope). |
| `created_by` | UserRef | null | Yes | — |
| `last_run` | ReportRun | null | Yes | See [ReportRun](#plan-reports-list-reportrun). |
| `created_at` | datetime | null | Yes | — |
| `updated_at` | datetime | null | Yes | — |

#### ReportRun object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `uuid` | uuid | Yes | — |
| `period_key` | string | Yes | The period the run covered, for example a date or an ISO week. |
| `scheduled_for` | datetime | Yes | — |
| `sent_at` | datetime | null | Yes | — |
| `status` | enum | Yes | `sent`, `failed` (see `error`) or `skipped_empty`. |
| `error` | string | null | Yes | A reason code when it failed. |
| `channel_message_id` | string | null | Yes | — |
| `email_count` | integer | Yes | How many emails went out. |
| `is_test` | boolean | Yes | `true` for a send-test; it does not count as the period's run. |

#### 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<ReportSchedule> | Yes | The page of [ReportSchedule](#plan-reports-list-reportschedule) objects. |
| `viewer` | RoutesViewer | Yes | A [RoutesViewer](#plan-notification-routes-list-routesviewer) 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. |

#### Example (curl)

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

#### Scenario examples

##### CLI

```bash
dailybot plan tasks reports list
```

##### Response

```bash
{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "uuid": "00000000-0000-4000-8000-000000000022",
      "name": "Friday wrap-up",
      "kind": "week_end",
      "enabled": true,
      "weekdays": [
        5
      ],
      "time": "16:00",
      "timezone": "America/Bogota",
      "channel": {
        "external_id": "C0123ABC",
        "name": "engineering",
        "type": "channel"
      },
      "email_recipients": [
        {
          "uuid": "00000000-0000-4000-8000-000000000001",
          "name": "Ana"
        }
      ],
      "scope": {
        "type": "all",
        "uuids": []
      },
      "created_by": {
        "uuid": "00000000-0000-4000-8000-000000000001",
        "name": "Ana"
      },
      "last_run": null,
      "created_at": "2026-09-30T14:00:00Z",
      "updated_at": "2026-09-30T14:00:00Z"
    }
  ],
  "viewer": {
    "can_manage": true
  }
}
```

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

**Schedule a report**

Organization administrators only. A daily report says what is expected today and who owns it; a week-start report looks at the week ahead; a week-end report says what closed, what is at risk and what did not close. It posts to a channel, goes by email to the people you name, or both, on the weekdays and local time you choose. At most 10 schedules per organization. Accepts `Idempotency-Key`.

- **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 | No | Schedule name. |
| `kind` | enum | No | `daily` (what is expected today, with owners), `week_start` (the week ahead) or `week_end` (what closed, what is at risk, what did not close). |
| `enabled` | boolean | No | Default `true`. |
| `weekdays` | array<integer> | No | ISO weekdays, Monday = 1 … Sunday = 7. A `daily` report takes any set (for example `[1,2,3,4,5]`); `week_start` and `week_end` take exactly one. |
| `time` | string | No | `HH:MM`, 24-hour, in `timezone`. |
| `timezone` | string | No | IANA name. Defaults to the organization's. |
| `channel` | object | null | No | `{external_id}` of the channel to post to, or `null` for email only. A schedule needs a channel, email recipients, or both. |
| `email_recipients` | array<uuid> | No | User uuids that receive it by email. `[]` clears them. |
| `scope` | RouteScope | No | `{type, uuids}`: the whole workspace, some boards or some projects. Members-only work is refused with `400 route_scope_not_org_visible`. |
| `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)` | ReportSchedule | Yes | A [ReportSchedule](#plan-reports-list-reportschedule) object. |

#### Error codes

| Status | When |
|--------|------|
| `400` | A schedule field is invalid (`invalid_schedule`, `extra.parameter` is `weekdays`, `time`, `timezone`, `channel` or `kind`), the channel is unknown (`channel_not_found`), the scope names members-only work (`route_scope_not_org_visible`), a field is unknown (`unknown_field`), or the organization already has 10 schedules (`report_schedules_limit_reached`, `extra.limit`). `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. |

#### Example (curl)

```bash
curl -sS -X POST "https://api.dailybot.com/v1/plan/reports/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Friday wrap-up",
  "kind": "week_end",
  "weekdays": [
    5
  ],
  "time": "16:00",
  "timezone": "America/Bogota",
  "channel": {
    "external_id": "C0123ABC"
  },
  "scope": {
    "type": "all",
    "uuids": []
  }
}'
```

#### Scenario examples

##### CLI

```bash
dailybot plan tasks reports create --name "Friday wrap-up" --kind week_end --weekday 5 --time 16:00 --channel C0123ABC
```

#### 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.
- Organization administrators only, with a login session, a CLI user token or a personal API key. Any member and any key may read.

### GET `/v1/plan/reports/{report_id}/` · Beta

**Retrieve a scheduled report**

One schedule. A schedule in another organization is `404`.

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

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `report_id` | uuid | Yes | The scheduled report's uuid. |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `(body)` | ReportSchedule | Yes | A [ReportSchedule](#plan-reports-list-reportschedule) 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. |
| `404` | The schedule does not exist in your organization (`not_found`), never a 403. |

#### Example (curl)

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

#### Scenario examples

##### CLI

```bash
dailybot plan tasks reports get 00000000-0000-4000-8000-000000000022
```

##### Response

```bash
{
  "uuid": "00000000-0000-4000-8000-000000000022",
  "name": "Friday wrap-up",
  "kind": "week_end",
  "enabled": true,
  "weekdays": [
    5
  ],
  "time": "16:00",
  "timezone": "America/Bogota",
  "channel": {
    "external_id": "C0123ABC",
    "name": "engineering",
    "type": "channel"
  },
  "email_recipients": [
    {
      "uuid": "00000000-0000-4000-8000-000000000001",
      "name": "Ana"
    }
  ],
  "scope": {
    "type": "all",
    "uuids": []
  },
  "created_by": {
    "uuid": "00000000-0000-4000-8000-000000000001",
    "name": "Ana"
  },
  "last_run": null,
  "created_at": "2026-09-30T14:00:00Z",
  "updated_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.

### PATCH `/v1/plan/reports/{report_id}/` · Beta

**Change a scheduled report**

Organization administrators only. Partial, with the same validation as create. `channel: null` clears the channel and `email_recipients: []` clears the recipients; clearing both is `400 invalid_schedule` (`extra.parameter: "channel"`).

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

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `report_id` | uuid | Yes | The scheduled report'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 | Schedule name. |
| `kind` | enum | No | `daily` (what is expected today, with owners), `week_start` (the week ahead) or `week_end` (what closed, what is at risk, what did not close). |
| `enabled` | boolean | No | Default `true`. |
| `weekdays` | array<integer> | No | ISO weekdays, Monday = 1 … Sunday = 7. A `daily` report takes any set (for example `[1,2,3,4,5]`); `week_start` and `week_end` take exactly one. |
| `time` | string | No | `HH:MM`, 24-hour, in `timezone`. |
| `timezone` | string | No | IANA name. Defaults to the organization's. |
| `channel` | object | null | No | `{external_id}` of the channel to post to, or `null` for email only. A schedule needs a channel, email recipients, or both. |
| `email_recipients` | array<uuid> | No | User uuids that receive it by email. `[]` clears them. |
| `scope` | RouteScope | No | `{type, uuids}`: the whole workspace, some boards or some projects. Members-only work is refused with `400 route_scope_not_org_visible`. |
| `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)` | ReportSchedule | Yes | A [ReportSchedule](#plan-reports-list-reportschedule) object. |

#### Error codes

| Status | When |
|--------|------|
| `400` | A schedule field is invalid (`invalid_schedule`, `extra.parameter` is `weekdays`, `time`, `timezone`, `channel` or `kind`), the channel is unknown (`channel_not_found`), the scope names members-only work (`route_scope_not_org_visible`), a field is unknown (`unknown_field`), or the organization already has 10 schedules (`report_schedules_limit_reached`, `extra.limit`). `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 schedule does not exist in your organization (`not_found`), never a 403. |

#### Example (curl)

```bash
curl -sS -X PATCH "https://api.dailybot.com/v1/plan/reports/00000000-0000-4000-8000-000000000022/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "weekdays": [
    1
  ],
  "kind": "week_start",
  "time": "09:00"
}'
```

#### Scenario examples

##### CLI

```bash
dailybot plan tasks reports update 00000000-0000-4000-8000-000000000022 --kind week_start --weekday 1 --time 09:00
```

#### 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.
- Organization administrators only, with a login session, a CLI user token or a personal API key. Any member and any key may read.

### DELETE `/v1/plan/reports/{report_id}/` · Beta

**Delete a scheduled report**

Organization administrators only. Its runs go with it. Answers `204`.

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

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `report_id` | uuid | Yes | The scheduled report'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` | 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 schedule does not exist in your organization (`not_found`), never a 403. |

#### Example (curl)

```bash
curl -sS -X DELETE "https://api.dailybot.com/v1/plan/reports/00000000-0000-4000-8000-000000000022/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN"
```

#### Scenario examples

##### CLI

```bash
dailybot plan tasks reports delete 00000000-0000-4000-8000-000000000022
```

#### 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.
- Organization administrators only, with a login session, a CLI user token or a personal API key. Any member and any key may read.

### GET `/v1/plan/reports/{report_id}/preview/` · Beta

**Preview a scheduled report with real data**

The report as it would be sent now: the same `ReportDocument` the chat message and the email are rendered from. Organization reports only ever include boards and projects the whole workspace can see.

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

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `report_id` | uuid | Yes | The scheduled report's uuid. |

#### ReportDocument object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `kind` | enum | Yes | `daily`, `week_start`, `week_end` or `personal_daily`. |
| `locale` | string | Yes | — |
| `header` | object | Yes | `{title, period_key, period_label, scope}`. |
| `sections` | array<ReportSection> | Yes | See [ReportSection](#plan-report-preview-reportsection). |
| `empty` | boolean | Yes | `true` when no section has items. |
| `narrative` | string | No | An optional short summary paragraph. |

#### ReportSection object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `key` | string | Yes | Stable section key, for example `closed`, `at_risk`, `due_today`. |
| `title` | string | Yes | — |
| `count` | integer | Yes | — |
| `empty` | boolean | Yes | — |
| `items` | array<ReportItem> | Yes | See [ReportItem](#plan-report-preview-reportitem). |

#### ReportItem object

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `type` | enum | Yes | `task`, `project`, `milestone`, `goal` or `text`. |
| `uuid` | string | Yes | — |
| `key` | string | No | The task key, such as `ENG-142`, when the item is a task. |
| `title` | string | Yes | — |
| `url` | string | Yes | Deep link into the web app. |
| `owner` | UserRef | No | — |
| `due_date` | date | No | — |
| `state` | string | No | — |
| `category` | string | No | — |
| `health` | string | No | — |
| `badges` | array<string> | Yes | Short flags such as `overdue` or `blocked`. |

#### 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 | — |

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `(body)` | ReportDocument | Yes | A [ReportDocument](#plan-report-preview-reportdocument) 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. |
| `404` | The schedule does not exist in your organization (`not_found`), never a 403. |

#### Example (curl)

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

#### Scenario examples

##### CLI

```bash
dailybot plan tasks reports preview 00000000-0000-4000-8000-000000000022
```

##### Response

```bash
{
  "kind": "week_end",
  "locale": "en",
  "header": {
    "title": "Week 40 wrap-up",
    "period_key": "2026-W40",
    "period_label": "Sep 28 \u2013 Oct 2",
    "scope": {
      "type": "all"
    }
  },
  "sections": [
    {
      "key": "closed",
      "title": "Closed this week",
      "count": 1,
      "empty": false,
      "items": [
        {
          "type": "task",
          "uuid": "00000000-0000-4000-8000-000000000011",
          "key": "ENG-142",
          "title": "Ship the onboarding checklist",
          "url": "https://app.dailybot.com/tasks/ENG-142",
          "owner": {
            "uuid": "00000000-0000-4000-8000-000000000001",
            "name": "Ana"
          },
          "due_date": "2026-10-01",
          "state": "Done",
          "category": "done",
          "badges": []
        }
      ]
    },
    {
      "key": "at_risk",
      "title": "At risk",
      "count": 0,
      "empty": true,
      "items": []
    }
  ],
  "empty": false
}
```

#### 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/reports/{report_id}/send-test/` · Beta

**Send a scheduled report now as a test, or preview what would be sent**

Organization administrators only. With `?dry_run=true` the document, the channel and the recipients are answered and nothing is sent. Without it the report is sent now and recorded as a test run (`is_test: true`); it does not count as the period's run.

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

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `report_id` | uuid | Yes | The scheduled report's uuid. |

#### Query parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `dry_run` | boolean | No | `true` renders and resolves only; nothing is sent or logged. Fails closed: any value other than `0`, `false`, `no` or `off` is a dry run. |

#### 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 |
|------|------|----------|-------------|
| `dry_run` | boolean | Yes | Echoes the request: `true` when nothing was sent. |
| `document` | ReportDocument | Yes | A [ReportDocument](#plan-report-preview-reportdocument) object. |
| `channel` | ChatChannel | null | Yes | A [ChatChannel](#plan-me-notifications-get-chatchannel) object. |
| `email_recipients` | array<UserRef> | Yes | The [UserRef](#plan-notification-routes-list-userref) objects. |
| `sent` | boolean | Yes | `false` on a dry run. |
| `run` | ReportRun | No | The test run when sent. See [ReportRun](#plan-reports-list-reportrun). |

#### 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 schedule does not exist in your organization (`not_found`), never a 403. |

#### Example (curl)

```bash
curl -sS -X POST "https://api.dailybot.com/v1/plan/reports/00000000-0000-4000-8000-000000000022/send-test/?dry_run=true" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN"
```

#### Scenario examples

##### CLI

```bash
dailybot plan tasks reports send-test 00000000-0000-4000-8000-000000000022 --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.
- Organization administrators only, with a login session, a CLI user token or a personal API key. Any member and any key may read.

### GET `/v1/plan/reports/{report_id}/runs/` · Beta

**A scheduled report's last runs**

The newest 20 runs, newest first: `sent`, `failed` (with a reason code) or `skipped_empty`. Test sends carry `is_test: true`.

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

#### Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `report_id` | uuid | Yes | The scheduled report's uuid. |

#### 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<ReportRun> | Yes | The [ReportRun](#plan-reports-list-reportrun) objects. |

#### 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 schedule does not exist in your organization (`not_found`), never a 403. |

#### Example (curl)

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

#### Scenario examples

##### CLI

```bash
dailybot plan tasks reports runs 00000000-0000-4000-8000-000000000022
```

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

**My daily briefing settings**

The caller's daily briefing settings, effective values. With nothing stored the answer is the default: the person's work days (Monday–Friday when they never changed them), `09:00` in their own timezone (`timezone_is_default: true`), chat on, email off, `enabled: false`. The chat leg is always a direct message, never the person's notification channel: the briefing holds their members-only work too.

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

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `enabled` | boolean | Yes | Whether the briefing is sent at all. |
| `weekdays` | array<integer> | Yes | ISO weekdays, Monday = 1. |
| `time` | string | Yes | `HH:MM`, 24-hour, in `timezone`. |
| `timezone` | string | Yes | IANA name. |
| `timezone_is_default` | boolean | Yes | `true` when the timezone is the person's own rather than one they set here. |
| `chat` | boolean | Yes | Deliver by direct message. |
| `email` | boolean | Yes | Deliver by email. |
| `skip_when_empty` | boolean | Yes | Skip the briefing on a day with nothing to say. |
| `effective` | boolean | Yes | `true` when the weekdays are the person's default work days rather than a set stored here. |
| `last_sent_at` | datetime | null | Yes | When the briefing last went out, or `null`. |

#### Error codes

| Status | When |
|--------|------|
| `400` | The credential is an agent or organization key (`actor_required`); this endpoint needs a person. |
| `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` | Guest accounts cannot use Plan (`guest_not_allowed`). |

#### Example (curl)

```bash
curl -sS "https://api.dailybot.com/v1/plan/me/briefing/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN"
```

#### Scenario examples

##### CLI

```bash
dailybot plan tasks briefing get
```

##### Response

```bash
{
  "enabled": true,
  "weekdays": [
    1,
    2,
    3,
    4,
    5
  ],
  "time": "09:00",
  "timezone": "America/Bogota",
  "timezone_is_default": true,
  "chat": true,
  "email": false,
  "skip_when_empty": true,
  "effective": true,
  "last_sent_at": "2026-09-30T14:00:00Z"
}
```

#### Notes

- Scope: `tasks:read`.
- Rate limit: 120 reads per minute per actor.
- Needs a person: call it with a login session, a CLI user token or a personal API key, which acts as its person. An agent or organization key gets `400 actor_required`.

### PUT `/v1/plan/me/briefing/` · Beta

**Change my daily briefing**

Partial: only the fields you send are written. `weekdays` are ISO 1..7, `time` is `HH:MM`, `timezone` is an IANA name (optional: the first write stores the person's own). At least one of `chat` and `email` must stay on. Refusals are `400 invalid_schedule` (`extra.parameter`) and `400 unknown_field`. Answers the full effective body.

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

#### 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 |
|------|------|----------|-------------|
| `enabled` | boolean | No | Whether the briefing is sent at all. |
| `weekdays` | array<integer> | No | ISO weekdays, Monday = 1 … Sunday = 7. |
| `time` | string | No | `HH:MM`, 24-hour. |
| `timezone` | string | No | IANA name. |
| `chat` | boolean | No | Deliver by direct message. |
| `email` | boolean | No | Deliver by email. |
| `skip_when_empty` | boolean | No | Skip the briefing on a day with nothing to say. |
| `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 |
|------|------|----------|-------------|
| `enabled` | boolean | Yes | Whether the briefing is sent at all. |
| `weekdays` | array<integer> | Yes | ISO weekdays, Monday = 1. |
| `time` | string | Yes | `HH:MM`, 24-hour, in `timezone`. |
| `timezone` | string | Yes | IANA name. |
| `timezone_is_default` | boolean | Yes | `true` when the timezone is the person's own rather than one they set here. |
| `chat` | boolean | Yes | Deliver by direct message. |
| `email` | boolean | Yes | Deliver by email. |
| `skip_when_empty` | boolean | Yes | Skip the briefing on a day with nothing to say. |
| `effective` | boolean | Yes | `true` when the weekdays are the person's default work days rather than a set stored here. |
| `last_sent_at` | datetime | null | Yes | When the briefing last went out, or `null`. |

#### Error codes

| Status | When |
|--------|------|
| `400` | A field is invalid (`invalid_schedule`, `extra.parameter` names it), unknown (`unknown_field`), both channels are off, the credential is an agent or organization key (`actor_required`), or 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` | Guest accounts cannot use Plan (`guest_not_allowed`). |

#### Example (curl)

```bash
curl -sS -X PUT "https://api.dailybot.com/v1/plan/me/briefing/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "enabled": true,
  "weekdays": [
    1,
    2,
    3,
    4,
    5
  ],
  "time": "08:30",
  "email": true
}'
```

#### Scenario examples

##### CLI

```bash
dailybot plan tasks briefing set --enable --weekday 1,2,3,4,5 --time 08:30 --email on
```

#### Notes

- Scope: `tasks:write`.
- 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, which acts as its person. An agent or organization key gets `400 actor_required`.

### GET `/v1/plan/me/briefing/preview/` · Beta

**Preview today's briefing**

Today's briefing for the caller, rendered now: the `personal_daily` `ReportDocument` with what is overdue, due today, in progress, blocked and next up, unread mentions and the projects the caller leads.

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

#### Response body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `(body)` | ReportDocument | Yes | A [ReportDocument](#plan-report-preview-reportdocument) object. |

#### Error codes

| Status | When |
|--------|------|
| `400` | The credential is an agent or organization key (`actor_required`); this endpoint needs a person. |
| `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` | Guest accounts cannot use Plan (`guest_not_allowed`). |

#### Example (curl)

```bash
curl -sS "https://api.dailybot.com/v1/plan/me/briefing/preview/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN"
```

#### Scenario examples

##### CLI

```bash
dailybot plan tasks briefing preview
```

#### Notes

- Scope: `tasks:read`.
- Rate limit: 120 reads per minute per actor.
- Needs a person: call it with a login session, a CLI user token or a personal API key, which acts as its person. An agent or organization key gets `400 actor_required`.

### POST `/v1/plan/me/briefing/send-test/` · Beta

**Send today's briefing to me now, or preview it**

With `?dry_run=true` nothing is sent. Without it, today's briefing goes to the caller by direct message and/or email, per their settings.

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

#### Query parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `dry_run` | boolean | No | `true` renders and resolves only; nothing is sent or logged. Fails closed: any value other than `0`, `false`, `no` or `off` is a dry run. |

#### 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 |
|------|------|----------|-------------|
| `dry_run` | boolean | Yes | Echoes the request: `true` when nothing was sent. |
| `document` | ReportDocument | Yes | A [ReportDocument](#plan-report-preview-reportdocument) object. |
| `sent` | boolean | Yes | `false` on a dry run. |

#### Error codes

| Status | When |
|--------|------|
| `400` | The credential is an agent or organization key (`actor_required`); this endpoint needs a person. |
| `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` | Guest accounts cannot use Plan (`guest_not_allowed`). |

#### Example (curl)

```bash
curl -sS -X POST "https://api.dailybot.com/v1/plan/me/briefing/send-test/?dry_run=true" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN"
```

#### Scenario examples

##### CLI

```bash
dailybot plan tasks briefing send-test --dry-run
```

#### Notes

- Scope: `tasks:write`.
- 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, which acts as its person. An agent or organization key gets `400 actor_required`.

---

## 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)
- [Plan · Home & search](/developers/api/plan-home)
- [Plan · Notifications & reports](/developers/api/plan-notifications) (this page)

**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)

