> For the complete documentation index, see [llms.txt](https://docs.clearfeed.ai/api/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.clearfeed.ai/api/reference/api-reference/announcements.md).

# Announcements

Create and track Slack announcements programmatically. An announcement's message body always comes from an existing Slack message — the API turns that message into an announcement and delivers it to the channels or collections you specify.

{% hint style="info" %}
`POST` requests require an API token with **Read & Write** scope. `GET` requests work with a **Read-only** token. See the [Authentication Guide](/api/quick-start/authentication-guide.md) for how to generate a token.
{% endhint %}

## Create and Send or Schedule an Announcement

<mark style="color:blue;">`POST`</mark> `https://api.clearfeed.app/v1/rest/announcements`

Creates an announcement from an existing Slack message and either sends it immediately or schedules it for later delivery.

### Request Body

| Name                                          | Type    | Description                                                                                                              |
| --------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------ |
| channel\_id<mark style="color:red;">\*</mark> | string  | Slack channel ID that contains the source message. The ClearFeed bot must be a member of this channel.                   |
| message\_ts<mark style="color:red;">\*</mark> | string  | Timestamp of the Slack message to use as the announcement body.                                                          |
| name<mark style="color:red;">\*</mark>        | string  | Announcement name. Only alphanumeric characters, spaces, hyphens, underscores, and apostrophes are allowed.              |
| recipients<mark style="color:red;">\*</mark>  | array   | At least one [recipient object](#recipient-object). Each entry is a Slack channel or a standard collection.              |
| action<mark style="color:red;">\*</mark>      | string  | `send_now` or `schedule`. Determines which of the [action-specific parameters](#action-specific-parameters) below apply. |
| sender\_config                                | object  | [Sender config object](#sender-config-object). Defaults to sending as the ClearFeed bot.                                 |
| unfurl\_links                                 | boolean | Whether to unfurl links in the message. Defaults to `false`.                                                             |
| unfurl\_media                                 | boolean | Whether to unfurl media in the message. Defaults to `false`.                                                             |

#### Action-Specific Parameters

`scheduled_time` is required when `action` is `schedule`, and must be omitted when `action` is `send_now`.

**`action: "send_now"`** — sends the announcement immediately. No additional parameters.

**`action: "schedule"`**

| Name                                              | Type   | Description                                              |
| ------------------------------------------------- | ------ | -------------------------------------------------------- |
| scheduled\_time<mark style="color:red;">\*</mark> | string | A future ISO 8601 datetime, e.g. `2026-07-10T09:00:00Z`. |

#### Recipient Object

| Name                                   | Type   | Description                                                                                                                                                        |
| -------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| type<mark style="color:red;">\*</mark> | string | `channel` to target a single Slack channel, or `collection` to target every channel in a standard collection.                                                      |
| id<mark style="color:red;">\*</mark>   | string | For `channel`, the Slack channel ID. For `collection`, the collection's `id` (see [Get Collections](/api/reference/api-reference/collections.md#get-collections)). |

#### Sender Config Object

| Name         | Type    | Description                                                                                                              |
| ------------ | ------- | ------------------------------------------------------------------------------------------------------------------------ |
| type         | string  | `clearfeed` (default) to send as the ClearFeed bot, `user` to send as a specific user, `topicOwner`, or `customerOwner`. |
| senderId     | string  | Required when `type` is `user`. Slack user ID of the sender.                                                             |
| useUserToken | boolean | Only applies when `type` is `user`. If `true`, sends using that user's Slack OAuth token instead of the bot token.       |

### Example cURL Request

```bash
curl --location 'https://api.clearfeed.app/v1/rest/announcements' \
--header 'Authorization: Bearer YOUR_API_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
  "channel_id": "C012AB3CD",
  "message_ts": "1719825600.000100",
  "name": "Q3 Update",
  "recipients": [
    { "type": "channel", "id": "C012AB3CD" },
    { "type": "collection", "id": "42" }
  ],
  "action": "schedule",
  "scheduled_time": "2026-07-10T09:00:00Z",
  "sender_config": { "type": "user", "senderId": "U01ABC123", "useUserToken": true },
  "unfurl_links": false,
  "unfurl_media": false
}'
```

### Response

| Name            | Type           | Description                                                                     |
| --------------- | -------------- | ------------------------------------------------------------------------------- |
| id              | number         | The newly created announcement's ID.                                            |
| status          | string         | `pending` for `send_now`, or `scheduled` for `schedule`.                        |
| scheduled\_time | string \| null | The ISO 8601 datetime the announcement is scheduled for. `null` for `send_now`. |

{% tabs %}
{% tab title="200: OK" %}

```json
{
  "announcement": {
    "id": 101,
    "status": "scheduled",
    "scheduled_time": "2026-07-10T09:00:00Z"
  }
}
```

{% endtab %}

{% tab title="400: Bad Request" %}

```json
{
  "message": "Collection with id 42 not found or is not a Slack collection",
  "error": "BAD_REQUEST"
}
```

{% endtab %}

{% tab title="403: Forbidden" %}

```json
{
  "message": "This API token has read-only access and cannot perform write operations.",
  "error": "FORBIDDEN"
}
```

{% endtab %}
{% endtabs %}

### Notes

* If any recipient (channel or collection) fails validation, the announcement is **not** created.
* Collection recipients must reference a standard (Slack) collection. Email, portal, and web-chat collections are rejected with a 400.
* This operation is recorded in [audit logs](/api/reference/api-reference/audit-logs.md) under the `Announcement` resource type.

## Retrieve Announcement Delivery Status

<mark style="color:blue;">`GET`</mark> `https://api.clearfeed.app/v1/rest/announcements/:id`

Retrieves an announcement's status and per-channel delivery details.

### Path Parameters

| Name                                 | Type    | Description                                                                                                                     |
| ------------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------- |
| id<mark style="color:red;">\*</mark> | integer | The announcement's ID, returned by [Create and Send or Schedule an Announcement](#create-and-send-or-schedule-an-announcement). |

### Example cURL Request

```bash
curl --location 'https://api.clearfeed.app/v1/rest/announcements/101' \
--header 'Authorization: Bearer YOUR_API_TOKEN'
```

### Response

| Name            | Type           | Description                                                                                           |
| --------------- | -------------- | ----------------------------------------------------------------------------------------------------- |
| id              | number         | The announcement's ID.                                                                                |
| name            | string         | The announcement's name.                                                                              |
| status          | string         | `pending`, `scheduled`, or `sent`.                                                                    |
| scheduled\_time | string \| null | The ISO 8601 datetime the announcement is scheduled for. `null` unless `status` is `scheduled`.       |
| recipients      | array          | One record per delivered channel. Collection recipients are expanded into individual channel records. |

Each entry in `recipients` has the following shape:

| Name           | Type           | Description                                                                                         |
| -------------- | -------------- | --------------------------------------------------------------------------------------------------- |
| channel\_id    | string         | Slack channel ID the announcement was (or will be) delivered to.                                    |
| collection\_id | number         | Present only when this channel was targeted via a collection. Identifies which collection added it. |
| status         | string \| null | `success`, `fail`, or `null` while delivery is pending or scheduled.                                |
| message\_ts    | string \| null | Timestamp of the delivered Slack message. `null` until delivery succeeds.                           |
| error          | string \| null | Delivery error, present only when `status` is `fail`.                                               |

{% tabs %}
{% tab title="200: OK" %}

```json
{
  "announcement": {
    "id": 101,
    "name": "Q3 Update",
    "status": "scheduled",
    "scheduled_time": "2026-07-10T09:00:00.000Z",
    "recipients": [
      {
        "channel_id": "C012AB3CD",
        "status": null,
        "message_ts": null,
        "error": null
      },
      {
        "channel_id": "C045EF6GH",
        "collection_id": 42,
        "status": "success",
        "message_ts": "1719825800.000200",
        "error": null
      }
    ]
  }
}
```

{% endtab %}

{% tab title="400: Bad Request" %}

```json
{
  "message": "Validation failed (numeric string is expected)",
  "error": "BAD_REQUEST"
}
```

{% endtab %}
{% endtabs %}

### Notes

* This endpoint returns per-channel delivery status. Use [Retrieve Announcement Engagement Metrics](#retrieve-announcement-engagement-metrics) for reactions and replies.
* This operation is recorded in [audit logs](/api/reference/api-reference/audit-logs.md) under the `Announcement` resource type.

## Retrieve Announcement Engagement Metrics

<mark style="color:blue;">`GET`</mark> `https://api.clearfeed.app/v1/rest/announcements/:id/metrics`

Retrieves aggregate and per-channel engagement data for a sent announcement.

### Path Parameters

| Name                                 | Type    | Description                                                                                                                     |
| ------------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------- |
| id<mark style="color:red;">\*</mark> | integer | The announcement's ID, returned by [Create and Send or Schedule an Announcement](#create-and-send-or-schedule-an-announcement). |

### Example cURL Request

```bash
curl --location 'https://api.clearfeed.app/v1/rest/announcements/101/metrics' \
--header 'Authorization: Bearer YOUR_API_TOKEN'
```

### Response

| Name                | Type   | Description                                                       |
| ------------------- | ------ | ----------------------------------------------------------------- |
| id                  | number | The announcement's ID.                                            |
| channel\_count      | number | Number of recipient channels where delivery succeeded.            |
| reaction\_count     | number | Total number of reactions across delivered announcement messages. |
| reply\_count        | number | Total number of thread replies across recipient channels.         |
| channel\_engagement | array  | Engagement and delivery information for each recipient channel.   |

Each entry in `channel_engagement` has the following shape:

| Name               | Type           | Description                                                                                          |
| ------------------ | -------------- | ---------------------------------------------------------------------------------------------------- |
| channel\_id        | string         | Slack channel ID for this recipient channel.                                                         |
| status             | string         | `success` or `fail` delivery status for this channel.                                                |
| total\_reactions   | number         | Total number of reactions in this channel.                                                           |
| top\_reactions     | array          | Up to five emoji ordered by reactor count. Each entry contains `emoji` and the reactors' `user_ids`. |
| reply\_count       | number         | Number of replies in the announcement thread.                                                        |
| message\_ts        | string \| null | Slack message timestamp for the delivered broadcast copy.                                            |
| reply\_message\_ts | array          | Slack message timestamps for all thread replies, in chronological order.                             |
| request\_id        | number \| null | ClearFeed request ID for the announcement thread, if a request exists.                               |

{% tabs %}
{% tab title="200: OK" %}

```json
{
  "announcement": {
    "id": 101,
    "channel_count": 1,
    "reaction_count": 3,
    "reply_count": 2,
    "channel_engagement": [
      {
        "channel_id": "C012AB3CD",
        "status": "success",
        "total_reactions": 3,
        "top_reactions": [
          {
            "emoji": "thumbsup",
            "user_ids": ["U01ABC123", "U02DEF456"]
          },
          {
            "emoji": "eyes",
            "user_ids": ["U03GHI789"]
          }
        ],
        "reply_count": 2,
        "message_ts": "1788941657.277429",
        "reply_message_ts": ["1788941701.123400", "1788941750.567800"],
        "request_id": 4567
      }
    ]
  }
}
```

{% endtab %}

{% tab title="400: Bad Request" %}

```json
{
  "message": "Metrics are only available for sent announcements",
  "error": "BAD_REQUEST"
}
```

{% endtab %}
{% endtabs %}

### Notes

* Metrics are available only when the announcement status is `sent`.
* `top_reactions` includes at most five distinct emoji. `total_reactions` counts every reaction, including reactions outside that list.
* `reply_message_ts` is an empty array when a channel has no replies.
* `message_ts` can be `null` when delivery did not succeed.
* This operation is recorded in [audit logs](/api/reference/api-reference/audit-logs.md) under the `Announcement` resource type.

## Resync an Announcement

<mark style="color:blue;">`POST`</mark> `https://api.clearfeed.app/v1/rest/announcements/:id/resync`

Queues an update to every delivered copy of a sent announcement. This operation updates existing messages and does not send the announcement again.

### Path Parameters

| Name                                 | Type    | Description                                                                                                                     |
| ------------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------- |
| id<mark style="color:red;">\*</mark> | integer | The announcement's ID, returned by [Create and Send or Schedule an Announcement](#create-and-send-or-schedule-an-announcement). |

### Example cURL Request

```bash
curl --request POST 'https://api.clearfeed.app/v1/rest/announcements/101/resync' \
--header 'Authorization: Bearer YOUR_API_TOKEN'
```

### Response

{% tabs %}
{% tab title="202: Accepted" %}
The response has no body. ClearFeed updates the delivered copies asynchronously.
{% endtab %}

{% tab title="403: Forbidden" %}

```json
{
  "message": "This API token has read-only access and cannot perform write operations.",
  "error": "FORBIDDEN"
}
```

{% endtab %}

{% tab title="406: Not Acceptable" %}
Returned when the announcement has not been sent.

```json
{
  "message": "Only sent announcements can be resynced.",
  "error": "NOT_ACCEPTABLE"
}
```

{% endtab %}
{% endtabs %}

### Notes

* This endpoint requires an API token with **Read & Write** scope.
* This operation is recorded in [audit logs](/api/reference/api-reference/audit-logs.md) under the `Announcement` resource type.
