---
title: "Async broadcast announcement to selected chat rooms in an app (v2, tenant actor)"
method: POST
path: "/v2/apps/{appId}/chats/broadcast"
tags: ["Chats"]
---

# Async broadcast announcement to selected chat rooms in an app (v2, tenant actor)

`POST /v2/apps/{appId}/chats/broadcast`

## Request

- Base URL: `https://api.chat.ethora.com`
- URL: `https://api.chat.ethora.com/v2/apps/{appId}/chats/broadcast`
- Auth: one of:
  - HTTP bearer
  - HTTP bearer

**Auth**: Tenant Actor

Same operation as `/v2/chats/broadcast`, but the target app is explicit in the path.
This is the preferred route for backend / tenant-admin integrations.

Request body shape is identical to `/v2/chats/broadcast` (validated by the same
Joi schema in the backend), and the response envelope is identical too —
`{ ok: true, jobId, statusUrl }` returned with HTTP 202. The only differences
from the legacy route are auth model and how the target app is resolved
(path parameter + ACL check here vs. derived from the token there).

Auth model:
- `B2B Server JWT`: preferred as `Authorization: Bearer <JWT>`.
- `B2B Server JWT`: legacy `x-custom-token: <JWT>` is also accepted for backward compatibility.
- `User JWT`: `Authorization: Bearer <JWT>` is also accepted when the caller has access to the target app.

Provide chatNames (internal Ethora chat names, e.g. `<appId>_<uuid>`) or
chatIds (uuid-only, will be prefixed with `<appId>_` server-side), or set
allRooms=true to broadcast to every chat in the app. At least one of
chatNames / chatIds / allRooms is required.

## Path parameters

- `appId` string, required

## Request body

- object
  - `text` string, required: Message body to broadcast. Plain text; chat-component renders it as a system or regular message depending on `isSystemMessage`.
  - `allRooms` boolean: If true, broadcast to every chat in this app. Capped by `CHATS_BROADCAST_MAX_ROOMS` (default 5000). Mutually exclusive with `chatNames` / `chatIds`.
  - `chatNames` string[]: Array of internal chat names (`<appId>_<chatId>`) to target. Use this for the most reliable matching. Max 100 per call.
  - `chatIds` string[]: Array of `chatId` values (the part after `<appId>_`). Convenience shorthand; converted to `chatNames` server-side. Max 100 per call.
  - `metadata` object: Free-form JSON attached to each emitted message. Useful for partner integrations that need a correlation ID.
  - `dryRun` boolean: If true, validate + resolve the room list and return the same `jobId`/`statusUrl` shape as a real call, but do not send any messages. Use to preview the target set before committing.
  - `sender` object: Optional per-broadcast sender override stamped on the outgoing `<data>` element (`fullName / senderFirstName / senderLastName / photo`). Falls back to `app.broadcastSender` and then `app.displayName` when omitted. Without any of these, chat-component renders broadcasts as "Deleted User". Provide either `name` (split on first whitespace) or explicit `firstName` + `lastName`.
    - `name` string
    - `firstName` string
    - `lastName` string
    - `photoUrl` string, uri
  - `isSystemMessage` boolean: When true, chat-component renders the broadcast via its SystemMessage component (banner). Defaults to false so broadcasts look like regular messages from the configured sender.

## Response `202`

```
{ ok: true, jobId: string, statusUrl: string }
```
statusUrl is `/v2/apps/{appId}/chats/broadcast/{jobId}` — poll the
matching app-scoped job route, not `/v2/chats/broadcast/{jobId}`.

## Other responses

- `400`: Bad Request
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not Found
- `422`: Unprocessable Entity
- `500`: Internal Server Error

---

[API](https://skmtc.dev/ethora/apis/platform-api.md) · [All operations](https://skmtc.dev/ethora/apis/platform-api/llms.txt) · [OpenAPI document](https://skmtc.dev/ethora/apis/platform-api/revisions/01b6e64378ee?raw)
