# Broadcast

Part of AppEngine API Documentation. Full index: https://appengine.appmint.io/documentation.md
## GET /broadcast/unsubscribe

**Unsubscribe from a bulk email link**

`operationId: BroadcastController_unsubscribe`

The signed link every bulk email carries; never needs a login. The query carries the org, address, broadcast and signature (`orgid`, `e`, `b`, `s`). A valid link adds the address to the org's suppression list. `format=json` answers `{ success, email }` (or 400 `{ success: false, error }`); otherwise the visitor is redirected (302) to the org's own result page, or shown a plain confirmation page when the org has no site.

#### Signature

```http
GET /broadcast/unsubscribe (orgid?: string, e?: string, b?: string, s?: string, format?: string) -> A redirect, an HTML page, or JSON with `format=json`
```

#### Access

Public — no credentials required.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | BAD_LINK | This unsubscribe link is not valid. | The signature does not match. | — |

Plus the standard platform errors: `429`, `500`.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | query | string | yes |  |
| `e` | query | string | yes | Recipient email. |
| `b` | query | string | — | Broadcast id. |
| `s` | query | string | yes | Signature over org, email and broadcast. |
| `format` | query | "json" | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | A redirect, an HTML page, or JSON with `format=json` |
| `400` | This unsubscribe link is not valid. — The signature does not match. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /broadcast/audience/count

**Audience size per list**

`operationId: BroadcastController_countAudience`

For each list or group id (up to 50), how many people a send would reach — tagged customers included, unsubscribed and bounced addresses left out.

#### Signature

```http
POST /broadcast/audience/count (body) -> { <listId>: count }
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

```json
{
  "lists": [
    "newsletter",
    "vip"
  ]
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | { <listId>: count } |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /broadcast/suppression

**Suppression list**

`operationId: BroadcastController_getSuppression`

Addresses this org may not bulk-email: unsubscribed, complained or bounced. Newest change first, paged; `search` matches the address. Includes counts per reason.

#### Signature

```http
GET /broadcast/suppression (status?: string, search?: string, page?: integer, pageSize?: integer) -> Paged subscribers with counts
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `status` | query | string | — | One suppression status. |
| `search` | query | string | — |  |
| `page` | query | integer | — |  |
| `pageSize` | query | integer | — | Max 200. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Paged subscribers with counts |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /broadcast/suppression/remove

**Remove an address from suppression**

`operationId: BroadcastController_removeSuppression`

Puts an address back in circulation. Do this only at the recipient's own request.

#### Signature

```http
POST /broadcast/suppression/remove (body) -> { success, email, restored }
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | EMAIL_REQUIRED | email is required | No email. | — |
| `404` | NOT_SUPPRESSED | That address is not on the suppression list | Nothing to restore. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

```json
{
  "email": "ada@example.com"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | { success, email, restored } |
| `400` | email is required — No email. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | That address is not on the suppression list — Nothing to restore. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /broadcast/accounts/{id}/test

**Test a sending account**

`operationId: BroadcastController_testAccount`

Sends a test message through a sending account to confirm it works end to end. The cheapest check before a real broadcast — it catches an unverified domain or a broken provider credential before thousands of recipients do.

#### Signature

```http
POST /broadcast/accounts/{id}/test (id: string, body) -> The test result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Sends a real email.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | ACCOUNT_NOT_FOUND | Email account not found | No account has that id. | Check the id. |
| `400` | PROVIDER_NOT_CONFIGURED | Email provider not configured | The org has no email provider integration. | Configure the provider first. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /broadcast/health`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Email account id. |

### Request body

Optional test recipient.

```json
{
  "to": "ops@example.com"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The test result |
| `400` | Email provider not configured — The org has no email provider integration. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Email account not found — No account has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /broadcast/{id}/send

**Send a broadcast**

`operationId: BroadcastController_triggerSend`

Releases a broadcast to its recipient list. **This sends real email to real people and cannot be undone** — `cancel` only stops what has not yet been handed to the provider.

Before calling: check the recipient count on the broadcast, confirm the sending domain is verified, and send yourself a test. A broadcast can only be sent from a status that allows it; one already sending or sent is refused rather than duplicated.

#### Signature

```http
POST /broadcast/{id}/send (id: string) -> The send result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Irreversible, outward-facing bulk send.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | BROADCAST_NOT_FOUND | Broadcast not found | No broadcast has that id. | Check the id. |
| `400` | CANNOT_SEND | Cannot send broadcast with status "<status>" | The broadcast is already sending, sent or cancelled. | Duplicate it and send the copy. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /broadcast/{id}/cancel`
- `POST /broadcast/accounts/{id}/test`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Broadcast id. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The send result |
| `400` | Cannot send broadcast with status "<status>" — The broadcast is already sending, sent or cancelled. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Broadcast not found — No broadcast has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /broadcast/{id}/cancel

**Cancel a broadcast**

`operationId: BroadcastController_cancelBroadcast`

Stops a broadcast. Messages already handed to the provider **have been sent** — cancelling halts the remainder, it does not recall anything. Speed matters here.

#### Signature

```http
POST /broadcast/{id}/cancel (id: string) -> The result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Does not recall messages already sent.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | BROADCAST_NOT_FOUND | Broadcast not found | No broadcast has that id. | Check the id. |
| `400` | CANNOT_CANCEL | Cannot cancel broadcast with status "<status>" | The broadcast is already finished or was never started. | Nothing left to stop. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /broadcast/{id}/send`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Broadcast id. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The result |
| `400` | Cannot cancel broadcast with status "<status>" — The broadcast is already finished or was never started. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Broadcast not found — No broadcast has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /broadcast/{id}/duplicate

**Duplicate a broadcast**

`operationId: BroadcastController_duplicateBroadcast`

Copies a broadcast into a new draft — the way to re-send a campaign, since a sent broadcast cannot be sent again. The copy starts unsent, with no recipients marked as delivered.

#### Signature

```http
POST /broadcast/{id}/duplicate (id: string) -> The new draft
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | BROADCAST_NOT_FOUND | Broadcast not found | No broadcast has that id. | Check the id. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /broadcast/{id}/send`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Broadcast id. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The new draft |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Broadcast not found — No broadcast has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /broadcast/{id}/report

**Get a broadcast report**

`operationId: BroadcastController_getBroadcastReport`

Per-recipient outcomes for a broadcast, filterable by status — who was delivered to, who bounced, who complained. Bounces and complaints are the ones worth acting on: leaving them on the list degrades the sending domain's reputation.

#### Signature

```http
GET /broadcast/{id}/report (id: string, page?: integer, pageSize?: integer, runId?: string, status?: string) -> Per-recipient outcomes
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | BROADCAST_NOT_FOUND | Broadcast not found | No broadcast has that id. | Check the id. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /broadcast/{id}/stats`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Broadcast id. |
| `status` | query | string | — | e.g. `delivered`, `bounced`, `complained`. |
| `page` | query | integer | — | Page number (1-based). |
| `pageSize` | query | integer | — | Rows per page. |
| `runId` | query | string | — | One run of the broadcast; omit for the latest. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Per-recipient outcomes |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Broadcast not found — No broadcast has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /broadcast/{id}/stats

**Get broadcast statistics**

`operationId: BroadcastController_getBroadcastStats`

Aggregate figures for one broadcast — sent, delivered, opened, clicked, bounced, complained.

#### Signature

```http
GET /broadcast/{id}/stats (id: string, runId?: string) -> Statistics
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | BROADCAST_NOT_FOUND | Broadcast not found | No broadcast has that id. | Check the id. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /broadcast/{id}/report`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Broadcast id. |
| `runId` | query | string | — | One run of the broadcast; omit for the latest. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Statistics |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Broadcast not found — No broadcast has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /broadcast/domains/register

**Register a sending domain**

`operationId: BroadcastController_registerDomain`

Registers a domain with the email provider so mail can be sent from it. Registration is only the first step — the DNS records the provider returns must be published before the domain verifies and mail actually delivers.

#### Signature

```http
POST /broadcast/domains/register (body) -> The registration, with the DNS records to publish
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | PROVIDER_NOT_CONFIGURED | Email provider not configured | The org has no email provider integration. | Configure the provider first. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /broadcast/domains/auto-configure`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The domain.

```json
{
  "domain": "example.com"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The registration, with the DNS records to publish |
| `400` | Email provider not configured — The org has no email provider integration. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /broadcast/domains/register-email

**Register a sending address**

`operationId: BroadcastController_registerEmail`

Registers a single address rather than a whole domain. **Sends a verification email to that address** — the owner has to click it, so use an address someone actually reads.

#### Signature

```http
POST /broadcast/domains/register-email (body) -> The registration
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Sends a verification email.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | PROVIDER_NOT_CONFIGURED | Email provider not configured | The org has no email provider integration. | Configure the provider first. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /broadcast/domains/email-status/{email}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The address.

```json
{
  "email": "news@example.com"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The registration |
| `400` | Email provider not configured — The org has no email provider integration. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## DELETE /broadcast/domains/register/{domain}

**Unregister a domain**

`operationId: BroadcastController_unregisterDomain`

Removes a domain or address from the email provider. Anything configured to send from it stops delivering — check what uses it before removing.

#### Signature

```http
DELETE /broadcast/domains/register/{domain} (domain: string) -> The result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Breaks any sender still using it.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /broadcast/domains/register`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `domain` | path | string | yes | Domain or address. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /broadcast/domains/status/{domain}

**Check a domain's status**

`operationId: BroadcastController_checkDomainStatus`

Whether a domain is registered, what DNS records it needs, and whether they are live — the diagnostic when mail is not delivering. Live verification, not a cached flag.

#### Signature

```http
GET /broadcast/domains/status/{domain} (domain: string) -> Registration and DNS status
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /broadcast/domains/auto-configure`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `domain` | path | string | yes | Domain. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Registration and DNS status |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /broadcast/domains/email-status/{email}

**Check an address's verification**

`operationId: BroadcastController_checkEmailStatus`

Whether a registered sending address has been verified by its owner.

#### Signature

```http
GET /broadcast/domains/email-status/{email} (email: string) -> Verification status
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /broadcast/domains/register-email`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `email` | path | string | yes | Email address. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Verification status |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /broadcast/domains/auto-configure

**Auto-configure sending DNS**

`operationId: BroadcastController_autoConfigureDNS`

Publishes the provider's required DNS records automatically. **Only works for domains registered through this platform** — a domain hosted elsewhere has to have its records added at its own DNS provider.

It writes live DNS records, so it changes real resolution for the domain.

#### Signature

```http
POST /broadcast/domains/auto-configure (body) -> The result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Writes live DNS records.
- Only for domains registered through the platform.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /broadcast/domains/status/{domain}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The domain.

```json
{
  "domain": "example.com"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /broadcast/validate/domain/{domain}

**Validate a domain**

`operationId: BroadcastController_validateDomain`

Checks whether a domain is well-formed and plausibly usable for sending, before registering it.

#### Signature

```http
GET /broadcast/validate/domain/{domain} (domain: string) -> Validation result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /broadcast/domains/register`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `domain` | path | string | yes | Domain. |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Validation result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /broadcast/validate/email/{email}

**Validate an email address**

`operationId: BroadcastController_validateEmail`

Checks an address for form and deliverability signals. Worth running over an imported list — sending to invalid addresses produces bounces, and a high bounce rate is what damages sender reputation.

#### Signature

```http
GET /broadcast/validate/email/{email} (email: string) -> Validation result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /broadcast/health`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `email` | path | string | yes | Email address. |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Validation result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /broadcast/health

**Get sending health**

`operationId: BroadcastController_healthDashboard`

Deliverability health across sending accounts — bounce and complaint rates, provider standing. Read this before a large send: a degraded account will not improve by sending more through it.

#### Signature

```http
GET /broadcast/health () -> Sending health
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /broadcast/health/{accountId}/check`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Sending health |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /broadcast/health/{accountId}/check

**Run a health check on an account**

`operationId: BroadcastController_triggerHealthCheck`

Forces a fresh health evaluation of one sending account rather than reading the last computed figures.

#### Signature

```http
POST /broadcast/health/{accountId}/check (accountId: string) -> The health result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | ACCOUNT_NOT_FOUND | Email account not found | No account has that id. | Check the id. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /broadcast/health`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `accountId` | path | string | yes | Email account id. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The health result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Email account not found — No account has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /broadcast/activity

**Get email activity**

`operationId: BroadcastController_getEmailActivity`

The event stream for sent mail — deliveries, opens, clicks, bounces, complaints — filterable by date and event type.

#### Signature

```http
GET /broadcast/activity (limit?: integer, recipient?: string, startDate?: string, endDate?: string, event?: string) -> Activity events
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /broadcast/activity/{messageId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — |  |
| `event` | query | string | — | e.g. `bounce`, `open`, `click`. |
| `limit` | query | integer | — | Maximum rows. |
| `recipient` | query | string | — | Only this recipient address. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Activity events |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /broadcast/activity/{messageId}

**Get one message's activity**

`operationId: BroadcastController_getEmailDetail`

The full event history for a single message — the trace to run when a recipient says they never received something.

#### Signature

```http
GET /broadcast/activity/{messageId} (messageId: string) -> The message activity
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /broadcast/sent/{messageId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `messageId` | path | string | yes | Message id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The message activity |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /broadcast/channel-stats

**Per-channel stats**

`operationId: BroadcastController_getChannelStats`

Per channel, counted from the delivery log: sent today, sent this month, delivery rate and open rate.

#### Signature

```http
GET /broadcast/channel-stats () -> { <channel>: { sentToday, sentThisMonth, deliveryRate, avgResponseRate } }
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | { <channel>: { sentToday, sentThisMonth, deliveryRate, avgResponseRate } } |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /broadcast/stats

**Get email statistics**

`operationId: BroadcastController_getEmailStats`

Send and engagement figures over a date range.

#### Signature

```http
GET /broadcast/stats (aggregatedBy?: string, startDate?: string, endDate?: string) -> Statistics
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /broadcast/stats/summary`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — |  |
| `endDate` | query | string | — |  |
| `aggregatedBy` | query | string | — | Bucket size, e.g. `day`, `week`, `month`. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Statistics |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /broadcast/stats/summary

**Get a statistics summary**

`operationId: BroadcastController_getStatsSummary`

Headline figures over the last N days — the compact version for a dashboard tile.

#### Signature

```http
GET /broadcast/stats/summary (days?: integer) -> The summary
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /broadcast/stats`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `days` | query | integer | — | Look-back window in days. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The summary |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /broadcast/sent

**List sent messages**

`operationId: BroadcastController_getSentEmails`

Messages the org has sent, newest first.

#### Signature

```http
GET /broadcast/sent (recipient?: string, startDate?: string, endDate?: string, limit?: integer) -> Sent messages
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /broadcast/sent/{messageId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — |  |
| `endDate` | query | string | — |  |
| `limit` | query | integer | — |  |
| `recipient` | query | string | — | Only this recipient address. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Sent messages |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /broadcast/sent/{messageId}

**Get a sent message**

`operationId: BroadcastController_getSentEmailDetail`

One sent message with its content and delivery outcome — what the recipient was actually sent, which is the record to check in a dispute.

#### Signature

```http
GET /broadcast/sent/{messageId} (messageId: string) -> The message
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /broadcast/activity/{messageId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `messageId` | path | string | yes | Message id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The message |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

