Skip to main content
SONZAI

Proactive Messaging

How agents reach out to users on their own — via recurring schedules, one-off wakeups, or tenant-triggered events, delivered over SSE, polling, or webhooks.

Proactive messaging is when the agent initiates contact rather than responding to user input. Messages can originate from three sources — a recurring schedule, a one-off wakeup, or an event your backend triggers — and are delivered through three channels: the live SSE chat stream, a polling notifications API, or a webhook your server receives.

The proactive triangle — sources × delivery channels

Every proactive message is defined by a source (what triggers it) and a delivery channel (how the user receives it). Mix and match freely.

Sources (what triggers the message)

  • Scheduled Reminders — recurring cadence (daily / weekly / hourly). Developer-configured. Use when a message must repeat on a predictable rhythm — medication reminders, habit nudges, daily check-ins.
  • Wakeups — a single one-off message at a specific moment, expressed as a delay from now. Agent- or developer-initiated. Use for birthdays, post-purchase follow-ups, or any event that fires exactly once.
  • Trigger Event — your backend calls TriggerEvent when something non-conversational happens (level-up, milestone, external state change). Use when the message is reactive to your own system events rather than time.

Delivery channels (how the user receives it)

  • SSE (live chat stream) — if the user has an active chat stream open, the proactive message appears inline in their conversation automatically.
  • Polling (client.agents.notifications.*) — your frontend or backend polls the notifications API on a schedule. Works well for web dashboards and mobile apps that check for new content when they foreground.
  • Webhooks — register a URL once; Sonzai POSTs every proactive message to it. Use for push notifications, email/SMS fanout, or any server-to-server integration.

Decision flow — which pattern do I pick?

  • Does the message need to repeat on a cadence?Scheduled Reminders
  • Is it a one-off event with a known fire time?Wakeups
  • Is it triggered by a non-conversational event in your backend? → Trigger Event (coming soon)
  • Should the user see it inline in their chat? → SSE (automatic when a chat stream is active — no extra code needed)
  • Is your frontend the primary consumer?Notifications polling
  • Do you need server-to-server delivery or multi-channel fanout (email, SMS)?Webhooks

Combines with other features

With Inventory — live structured data at fire time

A schedule or wakeup can reference an inventory_item_id. At fire time the platform reads the item's current properties, so the agent always has up-to-date information — even if the item changed since the schedule was created.

// Schedule that reads live inventory data at every fire
await client.schedules.create("agent_abc", "user_123", {
  cadence: { simple: { frequency: "daily", times: ["08:00"] }, timezone: "Asia/Singapore" },
  intent: "remind the user about their medication",
  check_type: "reminder",
  inventory_item_id: "inv_01HX...",
});

With Memory — capturing reply signals

When a proactive message triggers a user reply, the memory layer captures the exchange automatically. Query those memories later to build engagement or adherence dashboards.

// After firing reminders, search memory for user responses
const memories = await client.agents.memory.search("agent_abc", {
  query: "medication taken",
  limit: 10,
});

Tutorials

Next steps

On this page