Skip to main content

In-App Messaging

Add a notification inbox to your web or mobile application. Users can view, read, and manage their notifications directly in your app. Send notifications via the API (server-side), and render them client-side with the React component or your own UI using the subscriber inbox API.

Features

  • Drop-in React Component — Ready-to-use inbox UI with bell icon, popover, and feed
  • Real-time Updates — WebSocket-powered live notifications
  • React Native Compatible — Hooks work in React Native (web components are web-only)
  • Preferences — Users control their notification settings per channel and category
  • Persistence — Notifications stored until read, archived, or deleted

Architecture

In-app messaging uses a two-layer authentication model:

LayerAuthPurpose
Server-sideAPI key (zy_live_*)Send notifications, manage subscribers
Client-sideSubscriber JWT tokenRead/manage inbox for a specific subscriber

Your backend generates a subscriber JWT token (valid for 7 days), passes it to the frontend, and the React component uses it for all client-side operations.

Quick Start

1. Create a Subscriber (Server-Side)

curl -X POST https://api.zyphr.dev/v1/subscribers \
-H "Authorization: Bearer zy_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"external_id": "user_123",
"email": "user@example.com",
"name": "John Doe"
}'

2. Generate a Subscriber Token (Server-Side)

curl -X POST https://api.zyphr.dev/v1/subscriber-inbox/token \
-H "Authorization: Bearer zy_live_your_key" \
-H "Content-Type: application/json" \
-d '{ "external_id": "user_123" }'

Response:

{
"data": {
"token": "eyJhbGci...",
"subscriber_id": "uuid-here",
"expires_in": 604800
}
}

3. Install the React Component

npm install @zyphr-dev/inbox-react

4. Add to Your App

import { ZyphrProvider, InboxBell, InboxPopover } from '@zyphr-dev/inbox-react';
import '@zyphr-dev/inbox-react/styles.css';

function App() {
return (
<ZyphrProvider subscriberToken={token}>
<InboxBell />
<InboxPopover />
</ZyphrProvider>
);
}

5. Send a Notification (Server-Side)

curl -X POST https://api.zyphr.dev/v1/inbox/send \
-H "Authorization: Bearer zy_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"subscriber_id": "uuid-from-step-2",
"title": "New Comment",
"body": "John commented on your post",
"action_url": "https://yourapp.com/posts/123#comments"
}'
action_url must be a full URL

The action_url field requires a fully qualified URL (e.g., https://yourapp.com/path). Relative paths like /path are rejected. Custom URL schemes (e.g., myapp://settings) are also accepted for mobile deep links.


React Component

See the full React Inbox SDK documentation for all components, hooks, and configuration options.

Provider Configuration

<ZyphrProvider
subscriberToken={token} // Required — JWT from POST /v1/subscriber-inbox/token
apiUrl="https://api.zyphr.dev" // Default
wsUrl="wss://ws.api.zyphr.dev" // Default
realtime={true} // Enable WebSocket updates (default: true)
theme="system" // 'light' | 'dark' | 'system' (default: 'system')
>
{children}
</ZyphrProvider>

Pre-Built Components (Web Only)

ComponentDescription
InboxBellBell icon with unread badge
InboxPopoverDropdown notification feed
InboxFeedFull-page notification list
NotificationItemSingle notification card
PreferencesPanelNotification preference management

Hooks (Web + React Native)

HookDescription
useInbox()Notifications, loading state, actions (markAsRead, archive, delete)
useUnreadCount()Unread notification count
useRealTime()WebSocket connection status
usePreferences()Notification preference management

Custom Rendering

import { useInbox } from '@zyphr-dev/inbox-react';

function CustomInbox() {
const { notifications, unreadCount, markAsRead, markAllAsRead, archive } = useInbox();

return (
<div>
<h2>Notifications ({unreadCount})</h2>
{notifications.map(n => (
<div key={n.id} onClick={() => markAsRead(n.id)}>
<h3>{n.title}</h3>
<p>{n.body}</p>
</div>
))}
</div>
);
}

Server-Side API

Send a Notification

Endpoint: POST /v1/inbox/send

Correct endpoint

The endpoint is /v1/inbox/send, not /v1/inbox. POST /v1/inbox returns 404.

curl -X POST https://api.zyphr.dev/v1/inbox/send \
-H "Authorization: Bearer zy_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"subscriber_id": "sub_uuid",
"title": "New Comment",
"body": "John commented on your post",
"action_url": "https://yourapp.com/posts/123",
"category": "comments",
"priority": "normal"
}'

Batch Send

Send up to 100 notifications in a single request:

curl -X POST https://api.zyphr.dev/v1/inbox/send/batch \
-H "Authorization: Bearer zy_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"notifications": [
{ "subscriber_id": "sub_1", "title": "Update", "body": "New features!" },
{ "subscriber_id": "sub_2", "title": "Update", "body": "New features!" }
]
}'

Notification Parameters

ParameterTypeRequiredDescription
subscriber_idstring (UUID)YesZyphr subscriber UUID (not your external user ID)
titlestringYesNotification title
bodystringNoNotification body text
action_urlstringNoFull URL to navigate to on click (must be http://, https://, or custom scheme)
action_labelstringNoButton label for action
image_urlstringNoImage URL to display
iconstringNoIcon name or URL
categorystringNoCategory for filtering/preferences
prioritystringNolow, normal, high, urgent
dataobjectNoCustom data payload
expires_atstringNoISO 8601 expiration datetime
subscriber_id vs user_id

The inbox API uses Zyphr's internal subscriber_id (UUID), not your external user ID. Create a subscriber first via POST /v1/subscribers with your external_id, then use the returned id as the subscriber_id for inbox operations. The push API accepts user_id (your external ID) directly.

Subscriber-Scoped API (Client-Side)

These endpoints are called by the React component using the subscriber JWT token. They can also be called directly for custom client-side integrations.

MethodEndpointAuthDescription
POST/v1/subscriber-inbox/tokenAPI KeyGenerate subscriber token
GET/v1/subscriber-inboxSubscriber JWTList notifications (paginated)
GET/v1/subscriber-inbox/unread-countSubscriber JWTGet unread count
GET/v1/subscriber-inbox/:idSubscriber JWTGet single notification
POST/v1/subscriber-inbox/:id/readSubscriber JWTMark as read
POST/v1/subscriber-inbox/read-allSubscriber JWTMark all as read
POST/v1/subscriber-inbox/:id/archiveSubscriber JWTArchive notification
DELETE/v1/subscriber-inbox/:idSubscriber JWTDelete notification
GET/v1/subscriber-inbox/preferencesSubscriber JWTGet preferences
PUT/v1/subscriber-inbox/preferencesSubscriber JWTUpdate preferences

Server-Side API (Admin)

MethodEndpointAuthDescription
POST/v1/inbox/sendAPI KeySend notification
POST/v1/inbox/send/batchAPI KeySend batch
GET/v1/inboxAPI KeyList all notifications
GET/v1/inbox/:idAPI KeyGet notification
POST/v1/inbox/:id/readAPI KeyMark as read
POST/v1/inbox/read-allAPI KeyMark all as read
GET/v1/inbox/unread/countAPI KeyGet unread count
POST/v1/inbox/:id/archiveAPI KeyArchive
DELETE/v1/inbox/:idAPI KeyDelete

Notification Lifecycle

  1. Created — Notification sent and visible in inbox
  2. Read — User clicked or marked as read
  3. Archived — Hidden from default view
  4. Expired — Past expiration date (auto-archived)
  5. Deleted — Permanently removed

React Native

The hooks work in React Native — the pre-built UI components (InboxBell, InboxPopover, InboxFeed) are web-only.

import { ZyphrProvider, useInbox, useUnreadCount } from '@zyphr-dev/inbox-react';
// Do NOT import styles.css in React Native

<ZyphrProvider subscriberToken={token} theme="light">
<YourNativeInboxScreen />
</ZyphrProvider>

Use useInbox() and useUnreadCount() to build your own native UI. See the React Inbox SDK docs for details.