> ## Documentation Index
> Fetch the complete documentation index at: https://docs.brainstormer.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Channel Health

> Per-agent channel health as the provider reports it, plus how many conversations a human operator is holding.

# Channel Health

One org-scoped read behind the dashboard's channel-health banner, the alert on an agent's Channels tab, and the badge on an agent row.

It answers a single question — **is this agent actually replying to people right now?** — from two directions that fail the same silent way:

* **What the provider says.** For WhatsApp Business, a background sweep asks Meta every 30 minutes whether the account may send at all and whether the number is still serving, then writes the verdict to the channel row. Before this existed, `agent_channels.health_status` had defaulted to `healthy` since 2026 and nothing had ever written it — a WhatsApp Business Account blocked by Meta for a lapsed payment method read as perfectly healthy for ten days.
* **How many conversations a human is holding.** When an operator replies from the WhatsApp Business app or takes a conversation in the inbox, the AI stops answering on that thread by design. Nothing surfaced the count, so an agent could be muted on most of its live conversations with no sign of it anywhere.

<Note>
  All API requests require a valid JWT token in the `Authorization: Bearer <token>` header. The API Gateway decodes the JWT and forwards auth context (`user-id`, `organization-id`, `user-email`, `x-platform-role`, `x-org-role`) as headers to downstream services.
</Note>

## Get Channel Health

<ParamField method="GET" path="/api/channels/health" />

Every agent in **your** organization that has an active channel or at least one conversation an operator is holding.

<Note>
  This endpoint takes **no parameters**. The organization is the one on your verified session, and an `organizationId` query parameter is ignored rather than honoured. Requires the `member` org role or higher — it returns an org-wide aggregate that cannot be narrowed by per-resource grants, so a `viewer` receives `403`.
</Note>

### Response (200)

<ResponseField name="success" type="boolean" />

<ResponseField name="data" type="object">
  <Expandable title="data">
    <ResponseField name="agents" type="object[]">
      <Expandable title="Agent">
        <ResponseField name="botId" type="string">Agent UUID.</ResponseField>
        <ResponseField name="botName" type="string">Agent name.</ResponseField>

        <ResponseField name="operatorActiveCount" type="number">
          Conversations whose `hitl_status` is `operator_active` right now — the AI is not replying on these. `escalated`, `approval_pending` and `paused` are deliberately **not** counted: only `operator_active` means a human currently holds the thread.
        </ResponseField>

        <ResponseField name="oldestOperatorActiveAt" type="string | null">
          ISO 8601. The **least recently touched** of those conversations — read it as "this one has been sitting longest", not as "the operator took over at". `conversations` records no timestamp for the HITL transition itself, only `updated_at`, which every message bumps.
        </ResponseField>

        <ResponseField name="channels" type="object[]">
          <Expandable title="Channel">
            <ResponseField name="channelId" type="string">Channel UUID.</ResponseField>
            <ResponseField name="channelType" type="string">`whatsapp_business`, `whatsapp`, `web`, …</ResponseField>

            <ResponseField name="healthStatus" type="string">
              `healthy` | `degraded` | `blocked` | `disconnected`.
            </ResponseField>

            <ResponseField name="lastError" type="string | null">
              The provider's own words about the fault — for Meta, the error code, its description and the suggested fix. `null` when healthy. Never carries a token or any other secret.
            </ResponseField>

            <ResponseField name="lastHealthCheckAt" type="string | null">
              ISO 8601, or `null` when no probe has ever run for this channel.
            </ResponseField>
          </Expandable>
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<Warning>
  **`healthy` is also the column default, so read it together with `lastHealthCheckAt`.** A channel with `healthStatus: "healthy"` and `lastHealthCheckAt: null` has never been probed — it is "nothing is known", not "verified working". Only WhatsApp Business channels are probed today; every other channel type reads the default. Do not render a green tick from the status alone.
</Warning>

### What each state means

| State | What has stopped | Where it is fixed |
| - | - | - |
| `blocked` | Meta refuses business-initiated messages for this account. Replies inside an open 24-hour window may still go out; templates and first contact will not. | **Meta Business Manager** — most often WhatsApp Manager → Payment settings. Reconnecting in Brainstormer does not clear it. |
| `degraded` | Meta has limited the account, or cut the number's quality rating or messaging tier. Open conversations keep working; new ones may be capped. | Usually resolves itself as quality recovers. |
| `disconnected` | The phone number is not `CONNECTED`, or Meta rejected the stored credentials. Nothing is being sent or received. | The agent's **Channels** tab — reconnect. |
| `healthy` | Nothing. | — |

### Example

```json theme={null}
{
  "success": true,
  "data": {
    "agents": [
      {
        "botId": "8f14e45f-ceea-467a-9c3c-6a2f1e4f8b21",
        "botName": "Origem Support",
        "channels": [
          {
            "channelId": "b0c1d2e3-4f56-4789-a0b1-c2d3e4f56789",
            "channelType": "whatsapp_business",
            "healthStatus": "blocked",
            "lastError": "Meta error 141006 — There is an error with the payment method — Add a valid payment method in WhatsApp Manager",
            "lastHealthCheckAt": "2026-09-29T10:02:11.000Z"
          }
        ],
        "operatorActiveCount": 34,
        "oldestOperatorActiveAt": "2026-09-19T17:28:00.000Z"
      }
    ]
  }
}
```

### Errors

| Status | Meaning |
| - | - |
| `401` | No verified session. |
| `403` | Org role is `viewer`. |
| `500` | The read failed. The database error is never echoed to the caller. |

## Notifications

A state change also emails the organization's **owners and admins** once, through the `whatsapp_channel_health` notification preference (on by default for those two roles, off for members and guests). One email when a channel enters an unhealthy state, one more when it recovers — never one per sweep.

The de-duplication marker is written only after the mail rail confirms a delivery, so a failed send is retried on the next sweep rather than silently recorded as sent.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.