# notification.sent

Built for agents. One event for every notification we would email the account owner: a scheduled post failed to publish (`type: post_failed`), or a connected account was disconnected (`type: account_disconnected`).

It carries the email's `subject` and `text`, references to the post or account, and the `actions` that resolve it, so an agent subscribes to one event and handles every notification the same way.

### Agents or state sync

Subscribe to `notification.sent` when an agent or automation reads the alert and acts on it. Subscribe to `post.platform.failed`, `post.failed`, `post.partial` and `account.disconnected` when your system keeps post and account state in sync: they carry the structured post or account and fire on every state change.

### When it fires

Once for each such notification, in near real time, regardless of the user's email toggles, and even when the owner has no email address or the email is held back by the sender's limits. It fires alongside `post.failed` and `account.disconnected`, which stay as they are.

The user's notification channel (Slack or Telegram) follows the email toggles, so it only receives the alerts whose toggle is on.

- `post_failed`: once the failure is final (a permanent error, or a temporary one on its last retry), once per publish attempt that failed, for scheduled posts only (not "post now"). `refs.platforms` lists every platform that failed in that attempt.
- `account_disconnected`: every time an account is disconnected, never for creator-profile accounts. `reason` says why.

### Payload notes

`text` is the email body without the greeting. When your content retention is set to keep no content, the post text is replaced by `Content not retained` and each platform error by a generic description of its category.

### How to act

Each entry of `actions` is a public API call with the ids already in the path: `retry_post` (`retryPost`, `POST /v1/posts/{postId}/retry`), `reconnect_account` (`getConnectUrl`, `GET /v1/connect/{platform}`) and `check_account` (`getAccountHealth`, `GET /v1/accounts/{accountId}/health`).

### Who receives it

Endpoints subscribed to `notification.sent`. Scoped endpoints receive it for their profiles and accounts. Restricted keys need the `publishing` resource group.




**Payload for `notification.sent`:**

- **id** (required) `string`: Stable webhook event ID: the dedupe key, also sent as the X-Zernio-Event-Id header and identical on every retry and redelivery. It identifies the event only, never an account or other resource.
- **profiles**: `WebhookProfiles` - See schema definition
- **test** `boolean`: Always true when present: only a sample sent by POST /v1/webhooks/test with an event carries it. Real deliveries never do.
- **event** (required) `string`: No description - one of: notification.sent
- **notification** (required) `object`: 
  - **category** (required) `string`: The email notification preference this notification belongs to. - one of: postFailures, accountIssues
  - **type** (required) `string`: No description - one of: post_failed, account_disconnected
  - **subject** (required) `string`: The email subject.
  - **text** (required) `string`: The email body as plain text, without the greeting.
  - **url** (required) `string` (uri): Dashboard link for the notification.
  - **refs** (required) `object`: 
    - **post** `object`: 
      - **id** (required) `string`: The post id, as in GET /v1/posts/{postId}.
    - **platforms** `array[object]`: Every platform of the post that failed in this notification.
      - **platform** (required) `string`: No description
      - **accountId** (required) `string`: No description
    - **account** `object`: 
      - **id** (required) `string`: The disconnected account id.
      - **platform** (required) `string`: No description
      - **username** (required) `string`: No description
      - **profileId** (required) `string`: No description
  - **reason** `string`: Why the account was disconnected. Only on account_disconnected.
  - **actions** (required) `array[object]`: API calls that act on the notification, with the ids already in the path.
    - **type** (required) `string`: No description - one of: retry_post, reconnect_account, check_account
    - **operationId** (required) `string`: The operationId of the public API call. - one of: retryPost, getConnectUrl, getAccountHealth
    - **method** (required) `string`: No description - one of: GET, POST
    - **path** (required) `string`: The request path.
- **timestamp** (required) `string` (date-time): UTC time at which Zernio generated this event. Retries and redeliveries keep the original value.