Monitoring WhatsApp channel health
Bird runs periodic health checks against your WhatsApp channel configuration and updates the channel's status whenever something changes. You can react to those changes in two ways:
- Webhooks โ receive a channel.updated event pushed to your endpoint as soon as the status changes
- Check API โ poll or trigger a check on demand and get structured diagnostic results including per-assertion detail
Common use cases:
- Alert your team when a channel transitions to warning or inactive
- Surface health details in an operations dashboard
- Diagnose the root cause of a status change (quality score, token expiry, etc.)
Prerequisites
To subscribe to webhooks you need a workspace access key with the webhooks:write permission. See Authentication for details.
The Check API uses the connector ID, not the channel ID. You can find the connector ID on your channel's detail page or in the connectorId field of any channel webhook payload.
Channel health webhooks
Bird runs a health check on each WhatsApp channel on a regular schedule. When the result differs from the current status, the channel is updated and a channel.updated webhook fires.
Exemple de code
Health check runs
โ assertions evaluated against Meta Graph API
โ channel status updated if changed
โ channel.updated webhook delivered to all matching subscriptions
The webhook carries the current channel object. It does not include the previous status or the individual assertion results that caused the transition โ use the Check API to retrieve those.
Subscribing
Subscribe once per workspace. Use the channelStatus event filter to limit delivery to specific status values.
Exemple de code
curl -X POST https://api.bird.com/workspaces/{workspaceId}/webhooks \
-H "Authorization: AccessKey {accessKey}" \
-H "Content-Type: application/json" \
-d '{
"service": "channels",
"event": "channel.updated",
"url": "{{webhook_url}}",
"signingKey": "{{signing_key}}",
"eventFilters": [
{ "key": "platformId", "value": "whatsapp" }
]
}'Exemple de code
curl -X POST https://api.bird.com/workspaces/{workspaceId}/webhooks \
-H "Authorization: AccessKey {accessKey}" \
-H "Content-Type: application/json" \
-d '{
"service": "channels",
"event": "channel.updated",
"url": "{{webhook_url}}",
"signingKey": "{{signing_key}}",
"eventFilters": [
{ "key": "platformId", "value": "whatsapp" },
{ "key": "channelStatus", "value": "warning" }
]
}'You can create multiple subscriptions with different channelStatus filters to route degradation and recovery alerts to different endpoints.
Webhook payload
Exemple de code
{
"service": "channels",
"event": "channel.updated",
"payload": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "warning",
"platformId": "whatsapp",
"name": "My WhatsApp Channel",
"connectorId": "f9e8d7c6-b5a4-3210-fedc-ba9876543210",
"identifier": "+15551234567",
"transactional": false,
"preferences": {
"disableProfileFetching": false,
"explicitMarketingOptOut": false,
"trackAdInitiatedThreads": false,
"ignoreSuppressionChecks": false,
"isPrivate": false,
"disallowMmLite": false
},
"connectionParams": [],
"settings": [],
"capabilities": {},
"createdAt": "2026-01-15T09:00:00Z",
"updatedAt": "2026-05-26T14:32:00Z"
}
}Payload fields
| Field | Type | Description |
|---|---|---|
| service | string | Always "channels" |
| event | string | Always "channel.updated" |
| payload.id | UUID | Channel ID |
| payload.status | string | New channel status โ see Status values |
| payload.platformId | string | Always "whatsapp" |
| payload.connectorId | UUID | Use this with the Check API |
| payload.identifier | string | Phone number in E.164 format |
| payload.updatedAt | ISO 8601 | Timestamp of this status change |
Status values
| Status | Meaning | Action |
|---|---|---|
| active | All health checks passing | No action needed |
| warning | One or more checks failing | Inspect via the Check API |
| inactive | WhatsApp subscription cancelled | Re-subscribe or delete the channel |
| setting-up | Provisioning in progress | Wait โ another webhook fires on completion |
| failed | Provisioning failed | Check connector configuration |
The webhook does not include the previous status or which check failed. Compare payload.status against your own last-known state, or call the Check API, to determine whether this is a degradation or a recovery.
What triggers a warning
A single failing assertion is enough to change the channel status to warning.
Access
| Condition | Detail |
|---|---|
| System user token invalid or expired | Meta returns 401 on WABA fetch |
| WABA not found or permissions removed | WABA ID invalid or app removed from Business Manager |
| Unexpected Meta API error | Includes non-timeout network failures |
| App not subscribed to WABA | Bird app unsubscribed from WABA webhooks |
| Phone number not found in WABA | Phone removed from WABA or permissions revoked |
| Phone number not accessible | Phone exists in WABA but cannot be fetched |
Phone number
| Condition | Detail |
|---|---|
| Phone status BANNED | Number banned by WhatsApp |
| Phone status DELETED | Number deleted from WhatsApp Business Manager |
| Phone status MIGRATED | Number moved to a different WABA |
| Phone status DISCONNECTED | Number cannot be registered |
| Phone status UNVERIFIED | Number not verified |
| Phone status UNKNOWN | Status indeterminate from Meta |
| Phone status RATE_LIMITED | Number is rate limited |
| Phone status PENDING | Registration pending |
| Code verification EXPIRED or NOT_VERIFIED | Verification code expired or not completed |
| Display name DECLINED, PENDING_REVIEW, or EXPIRED | Name review in a non-approved state |
| Display name NON_EXISTS | No display name set |
| Quality score YELLOW | Moderate user feedback signals |
| Quality score RED | Poor user feedback โ messaging limits may apply |
| Business verification rejected or revoked | Meta Business Account verification failed |
| Business unverified + messaging tier โค TIER_250 | Scaling path not completed |
| Business verification pending_need_more_info | More information required from Meta |
What does NOT trigger a warning
| Condition | Why |
|---|---|
| Meta API timeout on phone fetch | Resolves to indeterminate โ check skipped, status unchanged |
| Business verification pending | Resolves to indeterminate โ check skipped, status unchanged |
| Account review status unknown | Resolves to indeterminate โ check skipped, status unchanged |
| WABA inaccessible โ dependent assertions | Downstream assertions become indeterminate; only wabaAccess itself triggers warning |
Check API
The Check API returns structured diagnostic results with individual assertion names, statuses, and messages. Use it to determine the root cause after receiving a channel.updated webhook.
Bird runs two distinct sets of checks against a WhatsApp channel:
- Channel checks โ run by the Bird platform on a schedule against the Meta Graph API. These drive the channel status field and fire channel.updated webhooks.
- Connector config checks โ run on demand via POST /status/checks to validate the connector configuration.
Both appear in checks.results[].
Endpoints
Get current status
Exemple de code
GET /workspaces/{workspaceId}/connectors/{connectorId}/status
Exemple de code
curl https://api.bird.com/workspaces/{workspaceId}/connectors/{connectorId}/status \
-H "Authorization: AccessKey {accessKey}"Run a check now
Triggers an immediate check and returns results.
Exemple de code
POST /workspaces/{workspaceId}/connectors/{connectorId}/status/checks
Exemple de code
curl -X POST https://api.bird.com/workspaces/{workspaceId}/connectors/{connectorId}/status/checks \
-H "Authorization: AccessKey {accessKey}"Get check history
Exemple de code
GET /workspaces/{workspaceId}/connectors/{connectorId}/status/checks
Returns a paginated list of past check runs.
Example response
Exemple de code
{
"channel": {
"channelId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"platformName": "WhatsApp",
"status": "error",
"stage": "active"
},
"checks": {
"runAt": "2026-05-26T14:30:00Z",
"results": [
{
"name": "access",
"displayName": "Check MessageBird has the required access",
"status": "error",
"assertions": [
{
"name": "wabaAccess",
"status": "error",
"message": "Access to WhatsApp Business Account has been revoked"
},
{
"name": "appSubscribed",
"status": "indeterminate",
"message": "Unable to verify app subscription because the WhatsApp Business Account is not accessible"
},
{
"name": "accountReviewStatus",
"status": "indeterminate",
"message": "Unable to check account review status because the WhatsApp Business Account is not accessible"
},
{
"name": "businessVerificationStatus",
"status": "indeterminate",
"message": "Unable to check business verification status because the WhatsApp Business Account is not accessible"
},
{
"name": "phoneAccess",
"status": "indeterminate",
"message": "Unable to check phone number access because the WhatsApp Business Account is not accessible"
}
]
},
{
"name": "phoneHealth",
"displayName": "Check phone number health",
"status": "ok",
"assertions": [
{
"name": "phoneNumberStatus",
"status": "ok",
"message": "The phone number is connected in WhatsApp Business Manager."
},
{
"name": "phoneQualityScore",
"status": "ok",
"message": "The phone number quality score is high."
}
]
}
]
}
}Response fields
| Field | Description |
|---|---|
| checks.runAt | ISO 8601 timestamp of when the check ran |
| checks.results[].name | Check identifier โ see reference below |
| checks.results[].displayName | Human-readable check name |
| checks.results[].status | Highest severity across all assertions in this check |
| checks.results[].assertions[].name | Assertion identifier |
| checks.results[].assertions[].status | ok, warning, error, or indeterminate |
| checks.results[].assertions[].message | Human-readable explanation |
Assertion status meanings
| Status | Channel effect | Meaning |
|---|---|---|
| ok | Contributes to active | Assertion passed |
| warning | Channel โ warning | Issue detected, messaging may be affected |
| error | Channel โ warning | Issue detected, messaging likely affected |
| indeterminate | No change | Could not run โ a dependency assertion failed |
Both warning and error assertion statuses produce a channel status of warning. The difference is only visible in the assertion detail โ use message to understand severity.
Assertion reference
Channel checks
These run on a schedule and drive the channel status field.
Check: access โ "Check MessageBird has the required access"
wabaAccess โ Access to WABA
Fetches the WhatsApp Business Account from Meta. All other assertions in this check become indeterminate if this fails.
| Status | Cause |
|---|---|
| ok | WABA is accessible |
| error | Invalid or expired system user token |
| error | WABA not found or permissions removed |
| error | Unexpected Meta API error (including network failures) |
appSubscribed โ App subscribed to WABA
| Status | Cause |
|---|---|
| ok | Bird app is subscribed to the WABA |
| error | App is not subscribed, or token is invalid |
| indeterminate | wabaAccess failed โ cannot check |
accountReviewStatus โ Account review status
| Meta value | Status |
|---|---|
| APPROVED | ok |
| PENDING | error |
| REJECTED | error |
| unknown | indeterminate |
businessVerificationStatus โ Business verification status
| Meta value | Messaging tier | Status |
|---|---|---|
| verified | any | ok |
| not_verified | > TIER_250 | ok |
| not_verified | โค TIER_250 | warning |
| pending_need_more_info | any | warning |
| pending | any | indeterminate |
| rejected | any | error |
| revoked | any | error |
| unknown | any | indeterminate |
phoneAccess โ Access to phone number
| Status | Cause |
|---|---|
| ok | Phone number is accessible |
| error | Phone not found in WABA, or not accessible |
| error | Invalid or expired system user token |
| indeterminate | Meta API timed out |
| indeterminate | wabaAccess failed โ cannot check |
Check: phoneHealth โ "Check phone number health"
All assertions depend on phoneAccess being ok. If phoneAccess is not ok, all assertions here are indeterminate.
phoneNumberStatus โ Phone number status
| Meta status | Assertion status | Message |
|---|---|---|
| CONNECTED | ok | The phone number is connected in WhatsApp Business Manager. |
| RATE_LIMITED | warning | The phone number is rate limited in WhatsApp. |
| PENDING | warning | The phone number is pending in WhatsApp Business Manager. |
| RESTRICTED | warning | WhatsApp 24 hour messaging limit of <tier> reached. |
| DISCONNECTED | error | The phone number is unable to be registered. |
| UNVERIFIED | error | The phone number is not verified. Please reinstall or verify. |
| BANNED | error | The phone number is banned from WhatsApp. |
| DELETED | error | The phone number has been deleted. Please delete this channel. |
| MIGRATED | error | Migrated to another WABA. Please delete this channel. |
| UNKNOWN | error | Status unknown. Please contact support. |
When the phone is PENDING and account review is APPROVED, Bird automatically attempts re-registration. When DISCONNECTED with a verified code, Bird also attempts re-registration automatically.
codeVerification โ Code verification status
Skipped when phone status is CONNECTED, DELETED, MIGRATED, BANNED, RESTRICTED, or RATE_LIMITED.
| Meta value | Status | Message |
|---|---|---|
| VERIFIED | ok | The phone number is verified. |
| EXPIRED | error | Verification expired. Please reinstall or verify the phone number. |
| NOT_VERIFIED | error | Not verified. Please reinstall or verify the phone number. |
currentNameStatus โ Current display name status
Skipped when name status is NONE (business verification is pending).
| Meta value | Status | Message |
|---|---|---|
| APPROVED | ok | The display name is approved. |
| AVAILABLE_WITHOUT_REVIEW | ok | Ready to use without review. |
| DECLINED | warning | Display name declined by WhatsApp. |
| EXPIRED | warning | Display name change expired. Please submit a new request. |
| PENDING_REVIEW | warning | Display name is pending review. |
| NON_EXISTS | error | The display name doesn't exist. |
newNameStatus โ Pending display name change
Only present when a display name change is in progress.
| Meta value | Status | Message |
|---|---|---|
| APPROVED | ok | No display name changes pending. (Re-registration triggered automatically.) |
| PENDING_REVIEW | ok | The new display name is pending review. |
| AVAILABLE_WITHOUT_REVIEW | warning | Business verification must be completed to start name change review. |
| DECLINED | error | New display name declined. Please submit a new request. |
| EXPIRED | error | New display name expired. Please submit a new request. |
phoneQualityScore โ Quality score
Skipped for phone status PENDING, DELETED, MIGRATED, BANNED, UNKNOWN, or UNVERIFIED.
| Meta value | Status | Message |
|---|---|---|
| GREEN | ok | Quality score is high. |
| YELLOW | warning | Quality score is medium. |
| RED | error | Quality score is low. |
Connector config checks
These run when you call POST /status/checks or use the Run Check button in the Bird dashboard. They do not directly change the channel status.
Check: webhooksSubscription โ "Check webhooks subscription"
| Assertion | Status | When it fails |
|---|---|---|
| Access token valid | ok, error | Meta returns a status other than 200 or 403 |
| Subscribed ok | ok, error | Meta returns 200 but success is false |
Check: checkPhoneStatus โ "Check phone status"
| Assertion | Status | When it fails |
|---|---|---|
| Access token valid | ok, error | Meta returns status โ 200 |
| Quality score is GREEN | ok, error | quality_score.score โ GREEN |
| Number connected | ok, error | status โ CONNECTED |
Check: checkBusinessProfile โ "Check business profile"
| Assertion | Status | When it fails |
|---|---|---|
| Access token valid | ok, error | Meta returns 401 |
| Messaging product enabled | ok, error | messaging_product โ "whatsapp" |
A fourth check, checkNameStatus, runs only as a precondition during connector installation to verify the access token can read the phone's name status. It does not appear in ongoing check results.