Skip to content

Application Messaging Foundation Guide

Messaging routing concept

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. 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.

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.

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.

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.

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.

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.

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.

A topic is the event name on a channel. Publishers, Wait steps, Decision outcomes, and Conversation screens only match when they use the same string. Prefer the Publish Message / Wait for message dropdown. Do not invent a nearby name.

Allow every topic you use on the channel. A publish or reply with a topic the channel does not list is dropped.

Topic What it does Inbox item
client.review.requested Decision card in Needs Review decision
client.intake.submitted Task card in the Agency / Work Queue task
supervisor.review.requested Decision card for supervisor review decision
checklist.ready Task when a related checklist is ready task
client.decision.approve Client approved — wakes Wait —
client.decision.changes_requested Client requested changes — wakes Wait —
client.decision.reject Client rejected — wakes Wait —
supervisor.decision.approve Supervisor approved — wakes Wait —
supervisor.decision.escalate Supervisor escalated — wakes Wait —

The three client.decision.* topics are the set Use all client decision topics writes onto a Wait step.

Same channel, two item types: publish client.review.requested as decision for the Decision screen; publish client.intake.submitted as task for the Work Queue.

Publish client.review.requested (decision)
→ Decision screen
→ outcome publishes client.decision.approve | changes_requested | reject
→ Wait for message on those exact topics wakes

Wait for message listens for the reply topics, not the request topic. Notification Center is the ping; turning a preference off does not remove the queue card.

Maker page: Topics that perform work.

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.

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.

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.

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.

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.

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:

{
"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:

{
"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:

{
"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:

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

Receiver workflow reply step:

{
"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:

{
"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.

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.
  1. Optionally enter a CTA label and URL.
  2. Optionally set starts_at and expires_at.
  3. Leave Show on every screen enabled for app-wide broadcasts.
  4. 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:

[
{
"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:

{
"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:

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

Example body:

{
"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.

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:

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

Example contract fields:

[
{
"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.

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

Section titled “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.

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:

[
{
"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:

{
"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.

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.

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.

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

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.

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.

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.

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.

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.

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.