> For the complete documentation index, see [llms.txt](https://docs.notionapps.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.notionapps.com/automation/application-messaging-foundation-guide.md).

# 📨 Application Messaging Foundation Guide

## Application Messaging Foundation Guide

### Application Messaging Foundation Guide

![Messaging routing concept](https://4233028229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5ZqDXcVVffWUqEIZVhmn%2Fuploads%2F3N99vYj45F6n5fDVAAzZ%2Fnotionapps-messaging-screenshot-gallery.png?alt=media\&token=b62bd223-5268-48da-852d-051c24d62ba5)

> Support visual: this image shows Messaging as the app-level event routing layer. Screens, workflows, broadcasts, linked apps, webhooks, and activity logs all connect through a structured message hub.

> Current state: Messaging is part of **Automation (Beta Testing)**. This guide explains the Messaging engine; product, pricing, live demo, template provisioning, and entitlement language should follow the NotionApps Automation Current State Guide.

Application Messaging is the communication layer inside NotionApps. It lets an application send structured messages from one part of the app to another part of the app, to Workflow Foundation, to linked applications, to webhooks, and to admin-visible activity logs.

Use this guide when you need to decide whether Messaging is the right tool, configure it end to end, explain entitlement levels, connect it to Workflow Foundation, or troubleshoot a route that is not behaving as expected.

For a broader support-ready explanation of Automation, Workflow, Messaging, entitlements, examples, and troubleshooting, see the Automation, Workflow, and Messaging Support Handbook.

#### Short Answer

Messaging helps when an app event should be routed somewhere else.

Examples:

* A button click should start a workflow.
* A form submission should notify a manager.
* A workflow should tell another workflow that a step is complete.
* An app admin should broadcast a service announcement to every screen.
* A customer portal should send an approval request to an operations app.
* A record status change should trigger a webhook.
* A workflow should wait for a reply before it continues.
* A builder should dry-run a route before allowing live delivery.

The simple model is:

```
Source publishes message -> Messaging validates and routes it -> Subscriber receives message
```

Workflow Foundation decides what work should happen. Messaging moves the event, payload, request, reply, or announcement to the right destination.

The maker-facing setup model is even simpler:

```
Describe the business outcome -> Review what NotionApps will build -> Answer only the missing route questions -> NotionApps builds the route -> Dry-run before live use
```

This is the same product direction as Workflow Foundation: the maker should not have to understand every low-level object before they can build a useful app behavior.

Approval Management is the third Automation capability that sits beside Workflow and Messaging. Messaging can carry approval requests, replies, and conversation history, but it does not unlock Decision screens, Work Queue screens, or workflow approval setup. Those approval-specific surfaces require Approval Management entitlement.

#### What Messaging Is

Messaging is an application-level message bus. A message has a channel, an optional topic, optional contract information, a payload, and routing metadata. Messaging validates the message, finds matching subscribers, records activity, and delivers or previews the route depending on the builder action.

Messaging is most valuable when a NotionApps application needs a reliable, auditable way to coordinate app behavior without hard-wiring every button, workflow, screen, and external integration directly to every other object.

#### What Messaging Is Not

Messaging is not a replacement for Workflow Foundation. Workflow Foundation is where builders model decisions, record updates, waits, notifications, branches, and multi-step business processes.

Messaging is not just a notification UI. It can power announcements, but it also supports event routing, request/reply flows, workflow triggers, linked app coordination, and external API intake.

Messaging is not automatically an email or push notification service by itself. It creates the structured event and delivery path. A subscriber, workflow step, webhook, or future delivery provider can turn that event into an email, push notification, external API call, or in-app update.

Messaging is also not the entitlement gate for approval work. If a builder wants a reviewer to claim work, approve/reject a request, or use an approval work queue, the application needs Approval Management in addition to any Workflow or Messaging access used by the route.

#### Where To Manage It

Open an application in the builder and select **Messaging** in the left sidebar.

The Messaging builder area contains these pages:

| Page              | Use it for                                                                                                                                    |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| **Overview**      | The progressive messaging home. New work starts with the business outcome; existing work shows setup, testing, failure review, or management. |
| **Guided setup**  | The deeper setup workspace for route details, source/destination questions, route objects, and dry-runs.                                      |
| **Announcements** | Service messages that appear automatically on every end-user screen in the app.                                                               |
| **Channels**      | Message lanes and allowed topics for the application.                                                                                         |
| **Contracts**     | Payload schemas, examples, and published versions.                                                                                            |
| **Publishers**    | Sources that can send messages and subscribers that can receive them.                                                                         |
| **Activity**      | Route preview, test publishing, recent messages, and delivery inspection.                                                                     |

Messaging is also controlled from the admin panel. Admins can enable or limit it by subscription plan, account, or individual application.

Approval-heavy apps usually need three admin checks before launch:

1. Workflow Foundation is enabled for the route that does the work.
2. Messaging Foundation is enabled for requests, replies, conversations, or announcements.
3. Approval Management is enabled for Decision screens, Work Queue screens, and workflow approval setup.

#### Outcome-First Guided Setup

Messaging can still be managed through channels, topics, contracts, publishers, subscribers, and Activity. Those objects are necessary because they make routes auditable, testable, and supportable.

However, makers should usually start in **Overview**, not in the manual pages.

Overview asks the maker to describe the business outcome first. Examples:

```
Notify a supervisor when a form is submitted.
Broadcast an outage message to everyone using this app.
Start a conversation between a requester and reviewer.
Send a record-created event to a webhook.
```

NotionApps then recommends a pattern, asks the minimum follow-up questions, fills in the underlying Messaging objects, and creates the route when the maker chooses **Build this messaging route**.

**Overview Progressive Path**

Messaging Overview shows one current required step:

1. **Start with the outcome**: type the business result or choose a starter pattern.
2. **What NotionApps will build**: review the route plan after an outcome exists.
3. **Create the messaging route**: create or reuse the channel, contract, publisher, subscriber, and dry-run path.
4. **Test the route**: preview delivery when live publish access allows it.
5. **No required action right now**: manage existing messaging work, failures, announcements, or activity.

Secondary tools such as Continue work, Announcements, Manual objects, and Manage / monitor appear only after there is messaging work to manage. This keeps first-time setup self-serving while leaving advanced tools available.

**Guided Setup Steps**

| Step                             | What the maker sees                                            | What NotionApps prepares                                                                                           |
| -------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| 1. Describe what should happen   | A business-language textarea and a recommended route pattern.  | The likely route family, channel, topic, contract name, source type, subscriber type, fields, and payload example. |
| 2. Answer the numbered questions | Context-aware fields for the source, destination, and payload. | Real app-aware IDs for screens, forms, controls, workflows, data sources, and saved objects.                       |
| 3. Review the route plan         | Plain-language steps and missing-item warnings.                | A safe creation plan that explains what will be created or reused.                                                 |
| 4. Build and test                | A single **Build this messaging route** action.                | Channel, contract, published contract, publisher, subscriber, and dry-run route preview.                           |

**Current Recommended Patterns**

| Pattern                          | Generated channel/topic                       | Common use                                                      |
| -------------------------------- | --------------------------------------------- | --------------------------------------------------------------- |
| Notify the right person          | `notifications / work.notification.requested` | Supervisory review, exception alerts, assignments, escalations. |
| Broadcast an announcement        | `announcements / announcement.published`      | Maintenance notices, service messages, policy updates.          |
| Start or continue a conversation | `conversations / conversation.message.sent`   | Direct chat, group chat, approval comments, support threads.    |
| Send an event to another system  | `integrations / external.event.created`       | Webhooks, linked apps, external API handoffs.                   |

The recommended pattern does not remove power-user control. Advanced builders can still edit the generated values or use the manual pages directly. The important product behavior is that a normal maker can build a route by describing the result and selecting friendly app objects, without starting from channel names, contracts, or raw IDs.

**Why The Objects Still Matter**

The route objects are what make Messaging safe and operationally visible:

* Channels and topics make the route understandable.
* Contracts validate the payload shape.
* Publishers restrict what can send messages.
* Subscribers define what receives messages.
* Activity shows what happened, what matched, and what failed.

The outcome-first UI keeps those objects behind a guided process so normal makers can build without thinking like engineers.

#### The Core Concepts

**Channel**

A channel is a named lane for messages in one application.

Use channels for broad areas of communication:

```
notifications
approvals
tasks
orders
announcements
integrations
```

Channel names should be short, lowercase, and stable. The backend accepts letters, numbers, underscores, and hyphens.

**Topic**

A topic is an optional label inside a channel. Topics let one channel carry different message types.

Examples:

```
task.assigned
task.completed
approval.requested
approval.decided
order.created
order.cancelled
admin.broadcast
```

Use dot-separated topics. Prefer `noun.action` or `domain.event`.

**Publisher**

A publisher is the source that sends a message.

Supported source types:

| Source type  | Common use                                                   |
| ------------ | ------------------------------------------------------------ |
| `screen`     | A screen-level runtime event publishes to Messaging.         |
| `button`     | A button click publishes a message.                          |
| `form`       | A form submission publishes a message.                       |
| `record`     | Record create, update, or status change publishes a message. |
| `workflow`   | A workflow step publishes, requests, or replies.             |
| `api`        | An authenticated API caller publishes.                       |
| `linked_app` | Another approved app publishes into this app.                |

**Subscriber**

A subscriber is the destination that receives a matching message.

Supported subscriber types:

| Subscriber type   | Common use                                                |
| ----------------- | --------------------------------------------------------- |
| `workflow`        | Start or resume a workflow when a message arrives.        |
| `screen`          | Route a message to a screen-level experience.             |
| `control`         | Target a specific control or component.                   |
| `builder_monitor` | Make activity visible for builder/admin monitoring.       |
| `webhook`         | Send the message to an external URL or integration alias. |
| `linked_app`      | Deliver the message to another approved application.      |

**Contract**

A contract defines the expected payload shape for a message. Contracts are strongly recommended because they let builders and subscribers trust what the message contains.

A contract includes:

* Channel
* Optional topic
* Name
* Version
* Field definitions
* Example payloads
* Status, such as draft or published

Published contracts should be treated as stable. If the payload changes, create a new version, such as `1.1.0` or `2.0.0`.

**Message**

A message is the actual event, command, request, reply, system event, or admin broadcast that moves through Messaging.

Message types:

| Type      | Meaning                                                              |
| --------- | -------------------------------------------------------------------- |
| `event`   | Something happened. Subscribers may react, but no reply is required. |
| `command` | A sender asks a receiver to do something.                            |
| `request` | A sender asks for a response and provides reply information.         |
| `reply`   | A receiver responds to a request.                                    |
| `system`  | A platform/system-originated message.                                |
| `admin`   | An admin-originated message, such as an application announcement.    |

**Delivery**

A delivery is Messaging's attempt to route one message to one subscriber.

Delivery statuses include:

```
accepted
validated
queued
delivering
delivered
partially_delivered
acknowledged
failed
dead_lettered
expired
cancelled
```

If one message matches three subscribers, it can produce three deliveries.

**Payload Visibility**

Subscribers can choose how much payload data they receive or expose.

| Visibility      | Meaning                               | Recommended use                                                                                |
| --------------- | ------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `redacted`      | Sensitive contract fields are hidden. | Default for most routes.                                                                       |
| `metadata_only` | Only routing metadata is visible.     | Monitoring, logs, or receivers that only need to know that something happened.                 |
| `full`          | Full payload is visible.              | Only use when the receiver truly needs it and the entitlement allows sensitive payload access. |

#### When Messaging Helps

**Service Announcements**

Use **Messaging > Announcements** when an application admin needs to show an important notice inside the live app.

Best for:

* Scheduled maintenance notices
* Feature rollout notices
* Temporary service interruption banners
* "Action required today" reminders
* Internal operating notices for field teams or client portals

Announcements appear automatically on every screen through the app shell. The builder does not need to add a banner component to every screen.

**Button Driven Actions**

Use Messaging when a button should do more than its built-in action.

Examples:

* "Request approval" publishes `approval.requested`.
* "Escalate" publishes `ticket.escalated`.
* "Notify manager" publishes `notification.manager_requested`.
* "Generate report" publishes `report.requested`.

The button remains simple for the app user, while subscribers decide what work happens next.

**Form Submission Routing**

Use Messaging when one form submission should start multiple outcomes.

Examples:

* A client intake form starts onboarding, sends a notification, and records an audit event.
* A time-off request starts an approval workflow.
* A support ticket form routes to the correct team based on priority.
* A vendor registration form triggers review, status changes, and external webhook delivery.

The form publishes one event. Workflows and subscribers handle the rest.

**Record Lifecycle Events**

Use Messaging when record creation or updates should notify other parts of the app.

Examples:

* A task is assigned.
* A contract status changes to approved.
* A payment record is marked overdue.
* A project stage changes from discovery to delivery.
* A record is created by an external intake process.

Pair this with contracts so every downstream workflow knows which fields are available.

**Workflow To Workflow Coordination**

Use Messaging when one workflow needs to trigger or inform another workflow.

Examples:

* A nightly digest workflow publishes `digest.ready`.
* A fulfillment workflow publishes `shipment.created`.
* A compliance workflow publishes `review.required`.
* A parent workflow sends a request and waits for a child workflow to reply.

This keeps workflows smaller and easier to reason about.

**Linked Application Coordination**

Use Messaging when separate apps should coordinate without becoming one large app.

Examples:

* A customer portal sends an approval request to an internal operations app.
* A field service app sends incident data to a manager dashboard app.
* A vendor portal sends onboarding completion to an admin app.
* A sales intake app sends handoff data to a delivery app.

Linked app routing requires `inter_app_enabled`.

**External API Intake**

Use Messaging when an external system should publish structured data into NotionApps.

Examples:

* A checkout system publishes `order.created`.
* A CRM publishes `lead.qualified`.
* A scheduling tool publishes `meeting.booked`.
* An external automation tool publishes `webhook.received`.

External API publishing requires `external_api_enabled`.

**External Webhook Delivery**

Use Messaging when NotionApps should notify an outside system.

Examples:

* Send approval decisions to a CRM.
* Notify a data warehouse of a completed workflow.
* Trigger an external reporting pipeline.
* Post updates to a support or ticketing system.

Use `metadata_only` or `redacted` unless the external receiver truly needs the full payload.

**Builder Monitoring And Audit**

Use Messaging when you need visibility into what happened and where it went.

Examples:

* Dry-run a route before publishing.
* Confirm a contract validated successfully.
* See how many subscribers matched a message.
* Diagnose a failed delivery.
* Verify that a workflow received the expected payload.

Use **Messaging > Activity** for this work.

**Request And Reply Flows**

Use request/reply when the sender cannot continue until another workflow, app, or integration responds.

Examples:

* A purchase request waits for manager approval.
* A client onboarding flow waits for compliance review.
* A field report waits for supervisor confirmation.
* A customer portal waits for internal fulfillment status.

Request/reply becomes especially powerful when combined with Workflow Foundation's `wait_for_message` step.

For app-facing conversations, prefer one stable conversation or correlation value per business object:

```
timecard id
support ticket id
approval request id
workflow run id
linked app exchange id
```

Native Conversation screens use that value to keep replies together. They should show normal language to the end user, such as a conversation title, "Write a reply," and "Send," rather than raw channel, topic, source, target, or correlation IDs. If more than one conversation is available, the screen should feel like a chat inbox: one conversation opens by default, and the user can switch only when needed.

Participant fields are important for privacy. Include fields such as `employee_email`, `supervisor_email`, `requester_email`, `reviewer_email`, `recipient_email`, or `assignee_email` when publishing private conversation messages. Those fields let NotionApps show older and newer replies to the correct users without turning the screen into a public feed.

When a participant is already on a Conversation screen, new messages are delivered through the automation screen stream. The frontend receives refreshed screen state over server-sent events and falls back to 30-second polling if the stream is unavailable.

#### When Not To Use Messaging

Do not use Messaging when:

* A single button only needs to navigate to another screen.
* A form only needs to save a record and show a success message.
* A one-step workflow can directly perform the action without routing.
* The message payload would duplicate sensitive data without a subscriber need.
* The route is temporary and easier to run manually once.

Messaging is worth using when the event should be reusable, observable, validated, delivered to multiple places, or connected to workflows/apps outside the immediate screen.

#### Entitlements

Messaging access is controlled by entitlement level and scope.

The entitlement level decides what the app can do. The scope explains where that decision came from.

**Entitlement Levels**

Entitlement levels are hierarchical. Higher levels include the capabilities of lower enabled levels.

| Level                  | Builder visible                     | Configure drafts | Dry-run/live publish | Same-app routes  | Linked app routes | External API | Admin operations |
| ---------------------- | ----------------------------------- | ---------------- | -------------------- | ---------------- | ----------------- | ------------ | ---------------- |
| `disabled`             | Maybe, if the menu is visible       | No               | No                   | No               | No                | No           | No               |
| `removed`              | Maybe, for historical/support state | No               | No                   | No               | No                | No           | No               |
| `builder_draft_only`   | Yes                                 | Yes              | No                   | No live delivery | No                | No           | No               |
| `intra_app_enabled`    | Yes                                 | Yes              | Yes                  | Yes              | No                | No           | No               |
| `inter_app_enabled`    | Yes                                 | Yes              | Yes                  | Yes              | Yes               | No           | No               |
| `external_api_enabled` | Yes                                 | Yes              | Yes                  | Yes              | Yes               | Yes          | No               |
| `admin_enabled`        | Yes                                 | Yes              | Yes                  | Yes              | Yes               | Yes          | Yes              |

**Capability Flags**

The backend returns these flags in the Messaging Overview entitlement panel:

| Flag                       | What it means                                                                |
| -------------------------- | ---------------------------------------------------------------------------- |
| `enabled`                  | The entitlement is active and not disabled or removed.                       |
| `builder_enabled`          | Builders can use the Messaging builder surface.                              |
| `live_publish_enabled`     | Dry-runs and live publishes are allowed. This starts at `intra_app_enabled`. |
| `intra_app_enabled`        | Messages can route inside the same application.                              |
| `inter_app_enabled`        | Messages can route to approved linked applications.                          |
| `external_api_enabled`     | Authenticated external API publishing is allowed.                            |
| `admin_operations_enabled` | Admin-only messaging operations are allowed.                                 |

**Scope And Source**

Entitlements can be applied at different places:

| Scope          | Meaning                                                       |
| -------------- | ------------------------------------------------------------- |
| `application`  | This application has a specific override.                     |
| `account`      | The builder account has an override that applies to its apps. |
| `subscription` | The plan policy controls access.                              |
| `default`      | The system default controls access.                           |
| `none`         | No effective entitlement exists.                              |

If a builder says "Messaging is visible but I cannot publish," check both `level` and `scope` in Overview. A plan may allow the feature while an account or application override still disables it.

**Limits And Retention**

Entitlements can also include operational limits:

| Field                          | Meaning                                                  |
| ------------------------------ | -------------------------------------------------------- |
| `channel_limit`                | Maximum channels allowed for the entitlement.            |
| `message_limit`                | Maximum messages allowed for the entitlement window.     |
| `retention_days`               | How long message records should be retained.             |
| `payload_retention_days`       | How long full payload data should be retained.           |
| `allow_sensitive_payload_view` | Whether sensitive contract fields can be viewed in full. |
| `retention_ends_at`            | Date after which retained data is no longer available.   |

Use shorter payload retention for sensitive apps. Use `redacted` subscriber visibility unless a receiver truly needs full payload data.

**Which Entitlement Should I Use?**

Use `builder_draft_only` when:

* A builder needs to model channels/contracts before launch.
* You want setup work without any live runtime delivery.
* You are testing the UI or preparing documentation.

Use `intra_app_enabled` when:

* The app only needs internal messages.
* Buttons, forms, records, screens, and workflows stay in the same app.
* You need application announcements.

Use `inter_app_enabled` when:

* One app needs to send messages to another NotionApps app.
* You want customer portal to operations app handoffs.
* You want an internal admin app to receive events from multiple runtime apps.

Use `external_api_enabled` when:

* External systems publish into NotionApps.
* NotionApps must route messages to webhooks.
* You need API-driven integration testing.

Use `admin_enabled` when:

* Admin operations must inspect or manage messaging globally.
* Support needs elevated messaging controls.
* Internal operators need access beyond normal app builders.

#### Messaging Versus Workflow Foundation

Use this comparison when deciding where a behavior belongs.

| Need                                             | Use Messaging              | Use Workflow Foundation             |
| ------------------------------------------------ | -------------------------- | ----------------------------------- |
| Define an event name and payload                 | Yes                        | Sometimes                           |
| Validate payload shape                           | Yes, with contracts        | Sometimes, with workflow validation |
| Find matching destinations                       | Yes                        | No                                  |
| Record message routing activity                  | Yes                        | No                                  |
| Run multi-step business logic                    | No                         | Yes                                 |
| Create or update Notion records                  | No                         | Yes                                 |
| Branch based on conditions                       | No                         | Yes                                 |
| Wait for time or response                        | No, but it carries replies | Yes                                 |
| Show UI actions like open screen or refresh data | No                         | Yes                                 |
| Connect apps, webhooks, and workflows            | Yes                        | Often via Messaging steps           |

The best pattern is usually:

```
Messaging detects and routes the event.
Workflow Foundation performs the work.
Messaging records replies, follow-up events, and cross-app delivery.
```

#### Workflow Foundation Integration

Messaging and Workflow Foundation become powerful together because each tool does one job well.

Workflow Foundation can start from a message, publish a message, send a request, send a reply, or wait for a message.

Relevant workflow trigger:

```
message_received
```

Relevant workflow steps:

```
publish_message
send_message_request
send_message_reply
wait_for_message
```

**Pattern 1: Message Starts A Workflow**

Use this when a button, form, API call, linked app, or record event should start a workflow.

Messaging setup:

```
Channel: tasks
Topic: task.assigned
Contract: task_assignment@1.0.0
Publisher: button btn_assign_task
Subscriber: workflow wf_notify_assignee
Payload visibility: redacted
```

Workflow setup:

```json
{
  "trigger_definition": {
    "type": "message_received",
    "config": {
      "channel": "tasks",
      "topic": "task.assigned",
      "contract_name": "task_assignment",
      "contract_version": "1.0.0"
    }
  }
}
```

What happens:

1. The user clicks the button.
2. The button publisher emits `tasks/task.assigned`.
3. Messaging validates the payload.
4. The workflow subscriber matches.
5. Workflow Foundation starts `wf_notify_assignee`.

Use this pattern when an event should fan out to workflow logic.

**Pattern 2: Workflow Publishes A Message**

Use this when a workflow reaches a meaningful point and other systems should know about it.

Workflow step:

```json
{
  "type": "publish_message",
  "name": "Publish digest ready",
  "config": {
    "channel": "notifications",
    "topic": "digest.ready",
    "contract_name": "digest_ready",
    "contract_version": "1.0.0",
    "payload": {
      "digest_id": "digest_2026_06_24",
      "recipient_email": "manager@example.com",
      "summary": "3 tasks need review"
    }
  }
}
```

Possible subscribers:

* A builder monitor for audit.
* A webhook for an external notification service.
* A linked app that displays manager work queues.
* Another workflow that handles delivery preferences.

Use this pattern when workflow progress should become an event other parts of the system can observe.

**Pattern 3: Request And Reply Between Workflows**

Use this when one workflow needs another workflow, app, or integration to answer before it can continue.

Sender workflow step:

```json
{
  "type": "send_message_request",
  "name": "Request manager approval",
  "config": {
    "channel": "approvals",
    "topic": "approval.requested",
    "contract_name": "approval_request",
    "contract_version": "1.0.0",
    "reply_to": {
      "channel": "approvals",
      "topic": "approval.decided"
    },
    "timeout_seconds": 86400,
    "payload": {
      "approval_id": "approval_123",
      "requested_by": "owner@example.com",
      "amount": 4250,
      "reason": "Software renewal"
    }
  }
}
```

Receiver workflow trigger:

```json
{
  "type": "message_received",
  "config": {
    "channel": "approvals",
    "topic": "approval.requested"
  }
}
```

Receiver workflow reply step:

```json
{
  "type": "send_message_reply",
  "name": "Reply with approval decision",
  "config": {
    "reply_status": "completed",
    "payload": {
      "approval_id": "approval_123",
      "decision": "approved",
      "reviewed_by": "manager@example.com",
      "review_note": "Approved for renewal"
    }
  }
}
```

Sender workflow wait step:

```json
{
  "type": "wait_for_message",
  "name": "Wait for approval decision",
  "config": {
    "correlation_id": "payload.envelope.correlation_id",
    "timeout_seconds": 86400,
    "timeout_step_id": "step_escalate_if_no_reply"
  }
}
```

What makes this powerful:

* The sender does not need to know exactly how the receiver works.
* The receiver can be a workflow, linked app, or external integration.
* The request and reply stay auditable in Messaging activity.
* The wait step can time out and continue down an escalation path.

**Pattern 4: Workflow Controls UI After A Message**

Use this when a message should trigger immediate runtime UI actions.

Example:

1. A user submits a form.
2. The form publishes `request.created`.
3. A workflow starts from `message_received`.
4. The workflow evaluates priority.
5. The workflow returns UI actions:
   * `show_message`
   * `open_screen`
   * `refresh_screen_data`
   * `set_control_visibility`
   * `block_interaction`

This lets the app feel responsive while keeping the decision logic in Workflow Foundation.

**Pattern 5: Cross-App Handoff With Internal Processing**

Use this when one application should hand work to another application while each app keeps its own screens and workflows.

Example:

```
Customer Portal
  form submitted -> Messaging message customer.requested

Operations App
  linked_app subscriber receives customer.requested
  workflow creates internal review task
  workflow publishes customer.review_started

Customer Portal
  linked_app subscriber receives customer.review_started
  screen or workflow updates customer-visible status
```

This pattern is cleaner than trying to force every team into one oversized app.

**Pattern 6: External Intake With Internal Workflow**

Use this when an external tool sends data into NotionApps and the app needs to turn it into an internal process.

Example:

```
External checkout -> API publisher -> orders/order.created
Messaging contract validates payload
Workflow creates Notion record
Workflow branches based on order total
Workflow publishes order.ready_for_fulfillment
Webhook subscriber notifies fulfillment system
```

This makes NotionApps the operational workspace while still accepting external events.

#### End-To-End Setup Recipes

**Recipe 1: Publish A Service Announcement**

Use this when app admins need to show a message on every app screen.

1. Open **Messaging > Announcements**.
2. Enter a clear title.
3. Enter the message body.
4. Choose severity:
   * `info` for general notices.
   * `warning` for action-needed notices.
   * `critical` for incidents or blocking issues.
5. Optionally enter a CTA label and URL.
6. Optionally set `starts_at` and `expires_at`.
7. Leave **Show on every screen** enabled for app-wide broadcasts.
8. Click **Publish broadcast**.

Example:

```
Title: Scheduled maintenance
Severity: info
Message: We will perform maintenance tonight from 9-10 PM Eastern.
CTA label: View status
CTA URL: https://status.example.com
Starts at: 2026-06-25T21:00:00-04:00
Expires at: 2026-06-25T22:30:00-04:00
```

Behind the scenes, announcements use this standard route:

```
Channel: announcements
Topic: admin.broadcast
Contract: service_announcement@1.0.0
Message type: admin
```

Announcement lifecycle:

| Action                | Meaning                                        |
| --------------------- | ---------------------------------------------- |
| **Save draft**        | Store the announcement without showing it.     |
| **Publish broadcast** | Make it active when the time window allows it. |
| **Pause**             | Temporarily hide it.                           |
| **Resume**            | Show it again.                                 |
| **Archive**           | Retire it.                                     |

Users can dismiss a banner in their browser. Dismissal is remembered locally for that app.

**Recipe 2: Button Click Starts A Workflow**

Use this when a button should start business logic.

Channel:

```
Name: approvals
Topic: approval.requested
```

Contract:

```
Name: approval_request
Version: 1.0.0
```

Contract fields:

```json
[
  {
    "key": "record_id",
    "label": "Record id",
    "type": "record_reference",
    "required": true
  },
  {
    "key": "requested_by_email",
    "label": "Requested by",
    "type": "email",
    "required": true
  },
  {
    "key": "amount",
    "label": "Amount",
    "type": "number",
    "required": false
  }
]
```

Publisher:

```
Source type: button
Source: Button: Request approval
Channel: approvals
Topic: approval.requested
Contract name: approval_request
Contract version: 1.0.0
```

Subscriber:

```
Subscriber type: workflow
Destination: Workflow: Manager approval
Channel: approvals
Topic: approval.requested
Contract name: approval_request
Contract version: 1.0.0
Payload visibility: redacted
```

Test payload:

```json
{
  "record_id": "rec_123",
  "requested_by_email": "owner@example.com",
  "amount": 4250
}
```

Verification:

1. Activity dry-run shows one workflow subscriber.
2. Live publish creates one recent message.
3. The workflow run is created.
4. Failed deliveries remain zero.

**Recipe 3: Form Submission Notifies Multiple Destinations**

Use this when one form submission should trigger several outcomes.

```
Channel: intake
Topic: request.submitted
Contract: intake_request@1.0.0
Publisher: form form_client_intake
Subscribers:
  workflow wf_create_review_task
  webhook webhook_customer_success
  builder_monitor monitor_intake_events
```

Why this is useful:

* The form only publishes one event.
* Each subscriber can evolve independently.
* A dry-run can show all matched destinations before live delivery.
* The webhook can receive redacted data while the workflow receives full data if allowed.

**Recipe 4: External API Publishes Into NotionApps**

Use this when an outside system should send a structured event to an app.

Required entitlement:

```
external_api_enabled
```

Endpoint:

```http
POST /v1/application/{applicationId}/messaging/messages
```

Example body:

```json
{
  "channel": "orders",
  "topic": "order.created",
  "contract_name": "order_created",
  "contract_version": "1.0.0",
  "message_type": "event",
  "dry_run": true,
  "payload": {
    "order_id": "ord_1001",
    "customer_email": "customer@example.com",
    "total": 149.99
  },
  "metadata": {
    "source": "external_checkout"
  }
}
```

Use `dry_run: true` until the route preview matches the intended subscribers. Set `dry_run: false` only after contract validation and destination matching are correct.

**Recipe 5: Workflow Waits For A Reply**

Use this when a process should pause until another party decides something.

Sender:

```
Workflow step: send_message_request
Channel: approvals
Topic: approval.requested
Reply channel: approvals
Reply topic: approval.decided
Timeout seconds: 86400
```

Receiver:

```
Workflow trigger: message_received
Channel: approvals
Topic: approval.requested
Workflow step: send_message_reply
```

Sender continuation:

```
Workflow step: wait_for_message
Correlation id: payload.envelope.correlation_id
Timeout step: Escalate approval
```

Use this for approvals, confirmations, compliance review, fulfillment status, or any process that should wait for an answer.

#### Guided Setup

Use **Automation Home** first when a maker wants a guided route from a business outcome. Use **Messaging > Overview** when the builder already knows they are creating a Messaging route but still needs the self-serving progressive path. Use **Messaging > Guided setup** when support or an advanced builder needs the full setup workspace for channel, contract, publisher, subscriber, and dry-run details.

The recommended premium setup path is:

```
Automation Preflight checks
-> Automation Plain-language setup
-> Automation Guided testing preview
-> Generate objects
-> Messaging Overview for self-serving route setup
-> Messaging Guided setup or advanced Messaging pages only when deeper route tuning is needed
```

Automation preflight is especially useful because it tells the maker whether Messaging entitlement, live publish, external API, linked-app routing, app context, and activity visibility are ready before they touch manual Messaging configuration.

The wizard walks through:

1. Create a channel.
2. Create and publish a contract.
3. Attach a source.
4. Attach a destination.
5. Dry-run the route.

Recommended starter setup:

```
Channel: notifications
Topic: button.clicked
Contract name: button_click
Contract version: 1.0.0
Source type: button
Subscriber type: workflow
Payload visibility: redacted
```

Example payload:

```json
{
  "record_id": "example-record-id",
  "message": "A user clicked the button",
  "actor_email": "user@example.com"
}
```

Example contract fields:

```json
[
  {
    "key": "record_id",
    "label": "Record id",
    "type": "string",
    "required": false
  },
  {
    "key": "message",
    "label": "Message",
    "type": "string",
    "required": true
  },
  {
    "key": "actor_email",
    "label": "Actor email",
    "type": "email",
    "required": false
  }
]
```

**How Automation And Messaging Guided Setup Differ**

| Need                                                          | Start here                                                             |
| ------------------------------------------------------------- | ---------------------------------------------------------------------- |
| "I want to notify someone when this happens."                 | Automation                                                             |
| "I want to broadcast to all app users."                       | Automation                                                             |
| "I know the channel, topic, source, and subscriber I need."   | Messaging Overview, then Guided setup if full route details are needed |
| "I need to inspect delivery attempts or contract validation." | Messaging Activity                                                     |
| "I need to edit the exact publisher/subscriber route."        | Messaging Publishers                                                   |

If the route was generated from Automation, the support bundle and Route map should be reviewed before changing manual Messaging objects.

#### Context-Aware Source And Target Pickers

Messaging asks for source IDs and target IDs, but builders should not need to hunt through raw IDs manually.

When a source or destination field appears, start typing. The picker searches the application context and suggests matching objects.

Examples:

```
Button: Send notification
Form: New request
Workflow: Notify assignee
Screen: Task details
Control: Approve
Data source: Tasks
Current app: Operations Portal
```

Selecting a result fills the raw ID automatically.

You can still paste a manual ID when:

* The target is outside the current application context.
* The target is a webhook alias.
* The target is a linked application not currently loaded in the builder.
* Support has given you a specific internal ID.

Best practice:

* Select from suggestions whenever possible.
* Use stable aliases for webhook targets.
* Do not use display labels as IDs unless the system guarantees they are stable.

#### Native Automation Screens And Message-Aware Surfaces

Messaging can feed native app screens, not only workflows and webhooks. The builder can add screens such as Work Queue, Decision, Workflow Status, Conversation, Exception Resolution, Notification Center, Automation Launcher, Linked App Exchange, and Operator Console.

When a builder adds one of these screens:

* The screen-selection page uses distinct icons for each screen type so makers can tell queue, decision, status, conversation, notification, launcher, exchange, and console screens apart.
* The selected data source is only an app-context anchor for automation-native screens. Live screen content comes from workflow, messaging, announcement, queue, and operational runtime state.
* Source binding fields are context-aware. Builders search by friendly names instead of memorizing screen IDs, workflow IDs, channel names, topic names, conversation IDs, or linked application IDs.
* Hidden/internal screens are intentionally included. A hidden screen may still be a valid workflow or messaging destination when a route opens it during approval, support, onboarding, or service-announcement flows.
* Action routing fields are context-aware. Actions such as Claim, Complete, Approve, Reject, Acknowledge, Dismiss, Escalate, and Launch workflow can be pointed at screens or workflows by selecting friendly names.
* Simulation fields are context-aware. Builders can search app objects, recent messages, generated recipes, workflow runs, or paste runtime-only IDs when testing a native screen.

Use native automation screens when a message should become a durable user-facing surface:

| Need                                                  | Recommended screen   |
| ----------------------------------------------------- | -------------------- |
| A user needs a personal or team task inbox            | Work Queue           |
| A user must approve, reject, or request changes       | Decision             |
| A user or owner needs to see run progress             | Workflow Status      |
| A message route needs a private per-record discussion | Conversation         |
| Failed automation needs a manual recovery surface     | Exception Resolution |
| App-wide announcements should remain available        | Notification Center  |
| A user should manually start approved automations     | Automation Launcher  |
| Two linked apps exchange requests or payloads         | Linked App Exchange  |
| Owners need operational visibility                    | Operator Console     |

The rule of thumb is simple: Messaging routes the event, Workflow performs the work, and native automation screens make the state understandable inside the application.

For detailed setup and troubleshooting for each screen type, see the Native Automation And Operational Screen Guides.

#### Manual Setup

Use manual setup when you already understand the route you want.

**Step 1: Create A Channel**

Open **Messaging > Channels**.

Good channel names:

```
notifications
tasks
orders
approvals
integrations
```

Good topics:

```
task.assigned
task.completed
approval.requested
order.created
order.cancelled
```

Leave topics blank when the channel can accept any topic.

**Step 2: Create A Contract**

Open **Messaging > Contracts**.

Example:

```
Channel: tasks
Topic: task.assigned
Name: task_assignment
Version: 1.0.0
```

Fields:

```json
[
  {
    "key": "task_id",
    "type": "record_reference",
    "required": true
  },
  {
    "key": "task_title",
    "type": "string",
    "required": true
  },
  {
    "key": "assignee_email",
    "type": "email",
    "required": true
  },
  {
    "key": "due_date",
    "type": "date",
    "required": false
  }
]
```

Example payload:

```json
{
  "task_id": "rec_123",
  "task_title": "Review proposal",
  "assignee_email": "manager@example.com",
  "due_date": "2026-07-01"
}
```

Publish the contract before relying on it for live routes.

**Step 3: Create A Publisher**

Open **Messaging > Publishers**.

Button publisher example:

```
Source type: button
Source: Button: Assign task
Channel: tasks
Topic: task.assigned
Contract name: task_assignment
Contract version: 1.0.0
```

Workflow publisher example:

```
Source type: workflow
Source: Workflow: Daily digest
Channel: notifications
Topic: digest.ready
Contract name: digest_ready
Contract version: 1.0.0
```

API publisher example:

```
Source type: api
Source: external_checkout
Channel: orders
Topic: order.created
Contract name: order_created
Contract version: 1.0.0
```

**Step 4: Create A Subscriber**

Open **Messaging > Publishers** and use the Create subscription panel.

Workflow subscriber:

```
Subscriber type: workflow
Destination: Workflow: Notify assignee
Channel: tasks
Topic: task.assigned
Contract name: task_assignment
Contract version: 1.0.0
Payload visibility: redacted
```

Webhook subscriber:

```
Subscriber type: webhook
Destination: webhook_crm_task_assigned
Channel: tasks
Topic: task.assigned
Contract name: task_assignment
Contract version: 1.0.0
Payload visibility: metadata_only
```

Linked app subscriber:

```
Subscriber type: linked_app
Destination: app_operations_portal
Channel: approvals
Topic: approval.requested
Contract name: approval_request
Contract version: 1.0.0
Payload visibility: redacted
```

**Step 5: Test In Activity**

Open **Messaging > Activity**.

Use dry-run first.

Dry-run verifies:

* Payload is valid JSON.
* Payload matches the contract.
* Channel and topic are valid.
* Matching subscribers are found.
* Route preview is correct.
* No live delivery happens.

Then publish a live test message.

Production readiness checklist:

1. Contract is published.
2. Publisher is active.
3. Subscriber is active.
4. Dry-run route preview matches the intended destinations.
5. Live test creates a recent message.
6. Failed deliveries remain zero.
7. Payload visibility is set to the minimum needed level.

#### Contract Design

Contracts are the long-term agreement between publishers and subscribers.

Supported field types:

```
string
number
boolean
date
datetime
email
url
enum
object
array
record_reference
screen_reference
application_reference
user_reference
```

Recommended field rules:

* Mark fields required only when every publisher can always provide them.
* Use `email` for emails, not `string`.
* Use `record_reference` for NotionApps record IDs.
* Use `enum` when only a few values are allowed.
* Mark sensitive fields as sensitive so redaction can work.
* Add examples that look like real payloads.

Versioning recommendations:

| Change             | Version suggestion                                    |
| ------------------ | ----------------------------------------------------- |
| Add optional field | `1.1.0`                                               |
| Add required field | `2.0.0`                                               |
| Rename field       | `2.0.0`                                               |
| Remove field       | `2.0.0`                                               |
| Add enum option    | `1.1.0` if subscribers tolerate it, otherwise `2.0.0` |
| Change field type  | `2.0.0`                                               |

Do not edit a published contract in a way that breaks existing subscribers. Create a new version instead.

#### Naming Recommendations

Channels:

* Use short lowercase names.
* Prefer broad lanes, not one channel per tiny action.
* Use plural nouns when possible.
* Examples: `tasks`, `orders`, `approvals`, `notifications`.

Topics:

* Use dot-separated event names.
* Prefer `noun.action` or `domain.event`.
* Examples: `task.assigned`, `order.created`, `approval.requested`.

Contracts:

* Use snake case.
* Keep names specific to payload meaning, not the current UI.
* Version with semantic-style numbers.
* Examples: `task_assignment@1.0.0`, `order_created@2.1.0`.

Publishers:

* Name or choose the real source object when possible.
* Keep one publisher per meaningful source route.
* Avoid creating duplicate publishers for the same source/channel/topic.

Subscribers:

* Use one subscriber per receiver.
* Keep payload visibility conservative.
* Pause subscribers instead of deleting them when testing route changes.

#### Operations And Lifecycle

**Channels**

| Status     | Meaning                             |
| ---------- | ----------------------------------- |
| `active`   | Channel can be used.                |
| `paused`   | Channel is temporarily unavailable. |
| `archived` | Channel is retired.                 |

**Contracts**

| Status       | Meaning                                                   |
| ------------ | --------------------------------------------------------- |
| `draft`      | Editable and not yet stable.                              |
| `published`  | Stable version available for validation.                  |
| `deprecated` | Still known, but builders should move to a newer version. |
| `archived`   | Retired.                                                  |

**Publishers And Subscribers**

| Status     | Meaning                                              |
| ---------- | ---------------------------------------------------- |
| `active`   | Route participant is available.                      |
| `paused`   | Temporarily disabled without deleting configuration. |
| `archived` | Retired.                                             |

**Messages And Deliveries**

Use Activity to inspect:

* Message ID
* Channel and topic
* Contract name and version
* Status
* Route preview
* Matched subscribers
* Delivery attempts
* Delivery errors
* Dead-lettered messages

#### Security And Privacy

Use these defaults unless you have a specific reason not to:

* Use `redacted` payload visibility for subscribers.
* Mark sensitive contract fields as sensitive.
* Use `metadata_only` for monitoring subscribers.
* Give external webhooks only the fields they need.
* Keep payload retention shorter than message metadata retention.
* Use `external_api_enabled` only when the app needs inbound API publishing.
* Use `admin_enabled` only for admin/support operations.

For private end-user apps, runtime announcement delivery follows the existing end-user auth path. Public apps can display announcements without end-user auth.

#### Troubleshooting

**Messaging Is Visible But Access Is Disabled**

Check **Messaging > Overview**.

Common causes:

* Entitlement level is `disabled`.
* Entitlement level is `removed`.
* Scope is not the scope you expected.
* The account has an override that disables the plan policy.
* The application has an override that disables the account policy.
* The account is on a different plan than the policy that was enabled.

**Builders Can Configure But Cannot Publish**

Most likely entitlement is `builder_draft_only`.

This means:

* Builder UI is enabled.
* Draft setup is allowed.
* Live publish is not allowed.
* Dry-run may also be blocked because route preview uses publish validation.

Enable `intra_app_enabled` or higher for live delivery.

Also check Automation Preflight. If the maker started from a recipe, Preflight will show whether the route is blocked by Messaging access, Workflow access, app context, missing generated objects, or missing testing visibility.

**Announcements Do Not Show**

Check:

* Entitlement has `live_publish_enabled`.
* Announcement status is `active`.
* `show_on_every_screen` is true.
* `starts_at` is empty or in the past.
* `expires_at` is empty or in the future.
* The user did not already dismiss the announcement in that browser.
* The app is loading the current runtime shell.

**Route Preview Shows Zero Subscribers**

Check:

* Subscriber status is `active`.
* Subscriber channel exactly matches the message channel.
* Subscriber topic is blank or exactly matches the message topic.
* Contract name and version match.
* Destination ID is selected or manually entered.
* The subscriber is in the same app unless linked app routing is enabled.

**Contract Validation Fails**

Check:

* Payload is a JSON object.
* Required fields are present.
* Field values match contract types.
* Enum values are allowed.
* Contract name and version match a published version.
* Sensitive fields are marked intentionally.

**Button Messages Do Not Arrive**

Check:

* Publisher source type is `button`.
* The selected source is the actual button being clicked.
* Publisher status is `active`.
* Channel and topic match subscriber configuration.
* Runtime user is authenticated if the app is private.
* Workflow subscriber is active and published.

**Workflow Does Not Start From A Message**

Check:

* Workflow trigger type is `message_received`.
* Messaging subscriber type is `workflow`.
* Subscriber destination points to the intended workflow.
* Workflow is active or published as required by the workflow builder.
* Message channel/topic match the workflow trigger configuration.
* Contract name/version match if specified.

**Workflow Publishes But No One Receives**

Check:

* Workflow step uses `publish_message`, `send_message_request`, or `send_message_reply`.
* Step config includes the intended channel and topic.
* Contract is published if provided.
* Matching subscribers exist.
* Subscriber payload visibility is allowed by entitlement.
* Activity route preview shows the subscriber.

**Request/Reply Does Not Resume**

Check:

* `send_message_request` includes `reply_to.channel`.
* Receiver sends `send_message_reply`.
* Reply uses the same correlation ID, or leaves it blank so the trigger envelope is used.
* Sender's `wait_for_message` is waiting for the correct correlation ID.
* Timeout has not already moved the workflow to the timeout step.

**Webhook Subscriber Does Not Receive**

Check:

* Entitlement is `external_api_enabled` or higher if external delivery/API is required.
* Subscriber type is `webhook`.
* Destination alias or URL is correct.
* Payload visibility is not blocking required fields.
* External service is reachable.
* Delivery error details in Activity.

**Linked App Route Does Not Work**

Check:

* Entitlement is `inter_app_enabled` or higher.
* Application link is active.
* Source and target app IDs are correct.
* Channel mappings allow the route.
* Payload visibility policy allows the receiver to see what it needs.

#### Frequently Asked Questions

**Should I Start With Guided Setup Or Manual Setup?**

Use Overview for the first route in an app. Use Guided setup when you need the full route workspace. Use manual setup when you already know the channel, contract, source, and destination.

**Do I Need A Contract?**

Technically, no. Practically, yes for production routes.

Contracts prevent accidental payload drift and make workflow/webhook behavior predictable. Use no-contract messages only for experiments or very loose events.

**Can One Message Go To Multiple Subscribers?**

Yes. One message can match several subscribers. This is useful when one event should start a workflow, notify a webhook, and appear in builder monitoring.

**Can One Subscriber Listen To Multiple Topics?**

A subscriber can omit topic to listen to all topics on a channel, or specify a topic to listen only to that topic. Use broad subscribers carefully.

**Can I Pause A Route Without Deleting It?**

Yes. Pause publishers, subscribers, or announcements when you want to disable behavior temporarily. Archive when the route is retired.

**Should A Workflow Publish Directly Or Should The Original Button Publish?**

Use the button publisher when the button click itself is the meaningful event. Use a workflow `publish_message` step when the meaningful event happens after the workflow does some work, such as validation, branching, or record updates.

**Do Approval Screens Require Messaging?**

Not always. A Decision screen or Work Queue screen is controlled by Approval Management. Messaging is required when the approval experience also needs routed request/reply events, private conversation history, announcements, or channel-based notifications.

For a complete approval route, expect to use:

* Workflow Foundation for the process.
* Approval Management for claim, decision, and approval setup surfaces.
* Messaging Foundation when the process needs conversations, routed approval messages, announcements, or app-wide notifications.

**What Is The Difference Between An Event And A Request?**

Use `event` when subscribers can react independently and no reply is required. Use `request` when the sender needs an answer and provides a reply target.

**What Is The Difference Between Announcements And Messages?**

Announcements are a simplified builder experience for app-wide service banners. They still publish through Messaging under the hood using the standard `announcements/admin.broadcast` route.

Normal messages are more flexible. They can route to workflows, screens, controls, webhooks, builder monitors, and linked apps.

**Can Messaging Send Email?**

Messaging can create the event that should result in an email. The email itself should be sent by a workflow notification step, webhook, or future delivery subscriber. This separation keeps routing and delivery logic clean.

Workflow Notify uses Email as its default delivery channel. If a cloned or older workflow step does not explicitly store `channel`, the workflow validator and runtime treat it as `email`, and the builder writes the explicit default when the workflow is saved or published.

**Can Messaging Send Push Notifications?**

Messaging provides the event and routing foundation. Push delivery should be a subscriber/provider capability layered on top of Messaging. App-wide in-app announcements are available now through the Announcements page.

**How Do I Notify All Users Of An App?**

Use **Messaging > Announcements** for in-app broadcasts. Publish the announcement with **Show on every screen** enabled.

**How Do I Notify All Owners Or Builders Across Apps?**

Use admin operations to identify the affected accounts/apps, then use app-level announcements for in-app broadcasts or workflow/webhook delivery for external email/push channels. Cross-account owner notification is an admin operation, not a normal per-app builder route.

**How Do I Keep Sensitive Data Safe?**

Use contracts, mark sensitive fields, use `redacted` or `metadata_only` subscriber visibility, limit payload retention, and avoid sending full payloads to external systems unless required.

#### Recommended First Production Route

Start with one same-app workflow route:

```
Channel: notifications
Topic: button.clicked
Contract: button_click@1.0.0
Publisher: button btn_send_notification
Subscriber: workflow wf_handle_button_click
Payload visibility: redacted
```

Then verify:

1. Entitlement is `intra_app_enabled` or higher.
2. Contract is published.
3. Publisher is active.
4. Subscriber is active.
5. Activity dry-run matches one subscriber.
6. Live test creates one recent message.
7. Workflow receives the expected payload.
8. Failed deliveries remain zero.

Once this works, add more topics to the same channel or create a second channel for a genuinely separate message area.

#### Builder Checklist

Use this checklist before turning on a live route:

* The use case truly needs routing, observability, or reuse.
* Channel and topic names are stable.
* Contract is published.
* Payload examples are realistic.
* Sensitive fields are marked.
* Publisher source is selected from the context-aware picker when possible.
* Subscriber destination is selected from the context-aware picker when possible.
* Payload visibility is `redacted` or `metadata_only` unless full payload is required.
* Dry-run route preview matches expectations.
* Live test succeeds.
* Workflow runs, webhook calls, or linked app deliveries are verified.
* Entitlement level matches the route type.
* Retention settings are appropriate for the data.

#### Admin Checklist

Use this checklist when enabling Messaging:

* Choose the lowest entitlement level that supports the use case.
* Prefer `builder_draft_only` before launch.
* Use `intra_app_enabled` for same-app workflows and announcements.
* Use `inter_app_enabled` only when linked apps are needed.
* Use `external_api_enabled` only when external publishing or webhook delivery is needed.
* Use `admin_enabled` only for admin/support operations.
* Confirm scope is correct: plan, account, or application.
* Set channel and message limits if needed.
* Set payload retention shorter than message retention when sensitive data is present.
* Decide whether sensitive payload viewing is allowed.
* Document why an override exists.
