Skip to main content

Overview

Notifications surface async events from across your buyer workspace — campaign health, creative approvals, agent registrations, optimization suggestions, and more — through three channels: in-app (per-user feed), email (personal preferences plus an account address), and Slack (account-scoped webhook). Users manage their own in-app and personal email preferences. Admins manage the account email address, its event list, and Slack. The notification system gives every operator a structured event feed for things they care about — campaign health, creative approvals, agent registrations, optimization suggestions, and more. Each event is delivered to one or more channels (in_app, email, Slack). Users can opt into supported events; always-on operational alerts are delivered independently of those personal preferences.

Open the notification inbox in Murph

Buyer and storefront agents can open the Notifications Page in Murph. It lists a bounded page of events, lets you load older results, and keeps Read and Acknowledged as separate states. Both states apply only to the signed-in recipient: reading or acknowledging a broadcast event does not change another person’s inbox. The Page also shows the current primary-Slack settings for Product Updates and sustained source-health alerts. Changing delivery does not mark an inbox event read or acknowledged, and a successful Slack, email, or webhook attempt does not count as either action. Release history stays in the separate Release notes Page. For agent builders, v3 open_page({"page":"notifications"}) returns a persona-specific Page contract. Buyer and storefront operation aliases are explicit; if the launch contract is missing, the Page waits instead of silently trying another API surface.
All endpoints below are mounted under https://api.apostra.com/api/v2/ and are accessible to both buyer and storefront users (role-agnostic shared router). The notification feed is filtered server-side by your in_app opt-ins plus always-on operational event types. A user with no opt-ins can therefore still see required storefront health and approval events.

Event taxonomy

Notification types follow a resource.action taxonomy so agents can build workflows around stable event names. The full enum lives in apps/api/src/types/notifications.ts. A representative slice:

Campaign lifecycle

campaign.created, campaign.updated, campaign.healthy, campaign.unhealthy, campaign.completed, campaign.deleted

Creative review

creative.approved, creative.rejected, creative.changes_requested, creative.sync_started, creative.sync_completed, creative.sync_failed

Agent registry

salesagent.registered, salesagent.available, signalsagent.registered, outcomesagent.registered, salesagent.updated

Optimization

optimization.suggestion_received, optimization.suggestion_approved, optimization.suggestion_applied, optimization.suggestion_failed

Measurement & learning

measurement.received, measurement.stale, learning_cycle.completed, hypothesis.proven, hypothesis.disproven

System & syndication

system.warning, system.error, syndication.completed, syndication.failed, audience.synced

Storefront health & approvals (always-on)

inventory_source.unhealthy, source.action_required, source.action_resolved, salesagent.sync_action_required, storefront_adapter_credential.action_required, storefront.composition_paused, storefront.products_not_traffickable, storefront.liveness_degraded, storefront.liveness_recovered, media_buy.approval_requested, creative.review_requested, ad_server.approval_requested, inventory_shortfall.review_requested — operational alerts that bypass opt-in for the in-app feed. Storefront health/readiness, ad-server approval, and inventory-shortfall alerts use account notification settings. Media-buy and creative-review queue alerts use the primary or optional escalation audience configured for that approval class; email is sent only when the routing stage enables email. Slack is the one exception: even always-on types only post to Slack once you’ve added that event type to your Slack configuration’s enabled events — connecting Slack doesn’t turn these on by itself.
Optimization suggestions notify you only when there’s a decision to make. You get optimization.suggestion_received when a suggestion proposes a budget or bid change on a campaign and media buy that are both still active. A suggestion that carries no budget or bid change doesn’t notify — most often a media buy with no optimization goal, where the suggestion is pacing information only, but also any run where the optimizer settles on your current allocation. Neither does a suggestion whose campaign or media buy is no longer active by the time it reaches you. In both cases the suggestion is still recorded against the media buy and closed out, so nothing sits in your queue waiting on a decision you can’t make.
Your storefront’s liveness verdict flipping is a proactive notification. When the liveness.state on Get readiness flips away from live (to live_attention or live_critical), or a further worsening from live_attention to live_critical, you get a storefront.liveness_degraded notification carrying the verdict’s own reason line and fix path — you don’t have to notice the dot change color. Recovery back to live sends storefront.liveness_recovered. A storefront still in setup (state: "setup") never alerts — setup is not failure. Repeated sweeps of the same unchanged state never re-notify.If the same inventory-source change also opens source.action_required or resolves it with source.action_resolved, email recipients receive the specific source-action email only. The storefront.liveness_* event remains in the in-app notification history, so the storefront-level state change is still recorded without sending a second email for the same health change.
Each notification carries a status (success, error, warning, info) and a data object with resource IDs (campaignId, creativeId, salesAgentId, …) plus a human-readable message.
Pending storefront review now sends a notification. When a buyer submits a creative or media buy that’s waiting on a storefront operator’s decision, it still appears in the operator’s Approvals queue and via Murph — and it also notifies the configured approval audience. In-app is always on; email and Slack follow that approval class’s routing rule. See Reviewing buyer transactions for how operators review and act on pending items.Each approval notification opens straight to the review it is about. The in-app entry, the email’s Review creative / Review media buy button, and the Slack Open in Apostra link all open Approvals focused on that review or media buy, behind your normal sign-in (data.actionUrl carries the same app-relative path for API consumers). A creative-review notification also names the creative, the buyer, the creative’s format, and its size when the creative states one (data.creativeName, data.buyerName, data.creativeFormat, data.creativeSize, data.reviewRef). Notifications never carry the creative itself or a preview link: the live preview is created only when you open the review, because preview links expire after 15 minutes and die when the creative changes.

Synchronous creative sync errors

Creative sync failures are not always reported as notifications. When a media-buy create or update targets a library-only seller and sync_creatives fails before the media-buy request is sent, the API returns a synchronous error instead of continuing silently. Handle this as an API failure and retry after correcting the creative or seller issue. The message includes the seller and cause:

Channels

email and in_app preferences on /notification-preferences belong to the signed-in user. Admins manage the separate account email event list on /notification-email/opt-ins, but cannot inspect or change another user’s personal preferences. Slack settings are also account-scoped. Approval work for media buys and creative review is different: the approval routing rule names its primary users and any optional escalation users, and its channel settings decide whether those users also receive email or the customer Slack channel receives one post. A missing account notification email does not broadcast those routed approval classes to every active user. Ad-server and inventory-shortfall approvals still use account notification settings until dedicated routes are available.
Storefront health and readiness emails are always-on operational alerts. They go to the account notification address and active account users even when those users have no saved email opt-in. Changing or clearing a user’s opt-ins does not disable these alerts.

Per-user preferences

Operators control which events appear in their personal feed or reach their personal email address. Each user can read and replace only their own list.
1

List the user's current opt-ins

Returns { "optIns": [{ "notificationType": "campaign.unhealthy", "channel": "email" }, ...] }.
2

Replace opt-ins (full set)

PUT /notification-preferences replaces the user’s entire opt-in list. Send up to 200 entries.

Account-level email opt-ins (admin)

Admins set the recipient address and which event types should generate email.
Changing notificationEmail is sensitive — the recipient receives every email-routed event for the account (including alert details that may contain campaign IDs and account context). Treat the field like any other admin credential: restrict who can edit it, and audit changes. Mutations to notificationEmail are recorded on the audit log and visible in the buyer activity feed.
PUT /notification-email and PUT /notification-email/opt-ins require the caller to have the ADMIN or SUPER_ADMIN role. Pass notificationEmail: null to clear the account-wide recipient; per-user email delivery still follows the rules above.

Slack configuration (admin)

Slack delivery uses an Incoming Webhook URL. Webhooks are admin-only and stored at the account level.

Murph channel delivery settings

Product Updates and source outage alerts use your account’s primary Murph Slack channel rather than the incoming-webhook event filter above. An active account member can ask Murph to show or change these settings; Murph confirms the write before applying it. You can also use the shared v2 API:
List primary-channel delivery settings
Turn off Product Updates in the primary channel
Send a Slack alert after a source outage lasts 30 minutes
Source outage Slack alerts can be sent after 10, 30, or 60 minutes, or turned off. Each alert also includes controls for future outages. Turning these Slack alerts off does not disable immediate in-app or email health notifications. Product Updates currently support on/off only. Their delivery schedule is fixed; the API does not expose a frequency value that the sender cannot honor.
Email opt-ins and Slack enabledEventTypes are independent filters. The account-level email opt-in list (/notification-email/opt-ins) controls which events generate email; the Slack enabledEventTypes list on /slack-configuration is a separate per-channel filter applied to Slack delivery only. To get a Slack alert for a given event type, that type must be present in enabledEventTypes — the email opt-in list has no effect on Slack. Configure both lists independently to route the same event to the channels you want.
1

Create or update the webhook

The URL must start with https://hooks.slack.com/services/. Provide at least one event type — only events on this list are forwarded to Slack.
A Slack incoming-webhook URL is a credential: anyone who has the URL can post messages to that channel without authenticating. Never paste a real webhook URL into source files, tickets, screenshots, or shared docs. Store the URL in a secret manager and rotate it immediately if it leaks (revoke + reissue from the Slack app configuration).
2

Send a test message

Posts a confirmation message to the configured webhook so the team can verify delivery before relying on it.
3

Read the current configuration

The response masks the webhook URL by default.
4

Disable Slack delivery

Reading the in-app feed

The response includes the page of notifications, plus totalCount, unreadCount, and hasMore for pagination.
The list endpoint already filters to event types the calling user opted into on the in_app channel — there is no need to pass types from the UI. If the user has not opted into any in-app types the response is an empty array (with totalCount: 0).

Mark read / acknowledge

A notification has two completion states:
  • read — surfaced to the user; safe to demote in the UI.
  • acknowledged — the user has acted on it (e.g. approved a suggestion). The feed hides acknowledged items by default.

Endpoint reference

All endpoints validate the standard buyer auth context (customerId, userId, userRole). Admin-only endpoints reject non-admin callers with ACCESS_DENIED.

Notification subscriptions

The sections above configure channels, opt-ins, and admin-managed routing directly for each event type. A newer, more structured layer sits alongside that: a notification subscription is an authored record of what you want to hear about, when it should fire, where it should go, and who is allowed to change it.

What a subscription carries

A subscription names:
  • scope and content: what it’s about and how it renders (an alert, or a digest for a recurring summary);
  • a trigger: a recurring schedule, or a typed condition that fires when a metric crosses a line;
  • route references: which delivery destinations it’s aimed at; and
  • provenance and mutability: who installed it, and exactly which parts of it you’re allowed to change.
A subscription can also carry a delivery policy for quiet hours, dedupe, cooldown, recovery, and expiry.
No trigger type fires yet: neither a schedule nor a condition has an evaluator or delivery path behind it today, so creating or patching one in is rejected. The shape above is the ratified contract a future evaluator reads from — an Intelligence Unit (IU) allowance-consumption condition is the first one planned. Managing subscriptions (inspecting provenance, mutability, and routes) is available today through the v3 preview agent surface for enrolled accounts; authoring one that actually fires is not available yet.

Required versus optional notices

Every subscription carries provenance (who installed it) and mutability (exactly what you’re allowed to change about it): Your own subscriptions are fully yours: create them, edit their trigger and routes, or turn them off, freely, once a trigger type is live. A contract-, plan-, or system-managed notice is different. It exists because of a commercial fact you already agreed to, not a personal preference, so it stays visible and inspectable even when you’d rather not see it.

Boundaries

A subscription references delivery destinations; it doesn’t own them. The Slack webhook and account notification email you configure above (Slack configuration, Account-level email opt-ins) are where those credentials and addresses live: a subscription only points at them by reference and never carries a credential itself. And a subscription is for being told something, not for a machine-readable feed: a scheduled data export belongs to Reporting, not to a notification.