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:
| Layer | Auth | Purpose |
|---|---|---|
| Server-side | API key (zy_live_*) | Send notifications, manage subscribers |
| Client-side | Subscriber JWT token | Read/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"
}'
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)
| Component | Description |
|---|---|
InboxBell | Bell icon with unread badge |
InboxPopover | Dropdown notification feed |
InboxFeed | Full-page notification list |
NotificationItem | Single notification card |
PreferencesPanel | Notification preference management |
Hooks (Web + React Native)
| Hook | Description |
|---|---|
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
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
| Parameter | Type | Required | Description |
|---|---|---|---|
subscriber_id | string (UUID) | Yes | Zyphr subscriber UUID (not your external user ID) |
title | string | Yes | Notification title |
body | string | No | Notification body text |
action_url | string | No | Full URL to navigate to on click (must be http://, https://, or custom scheme) |
action_label | string | No | Button label for action |
image_url | string | No | Image URL to display |
icon | string | No | Icon name or URL |
category | string | No | Category for filtering/preferences |
priority | string | No | low, normal, high, urgent |
data | object | No | Custom data payload |
expires_at | string | No | ISO 8601 expiration datetime |
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.
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST | /v1/subscriber-inbox/token | API Key | Generate subscriber token |
GET | /v1/subscriber-inbox | Subscriber JWT | List notifications (paginated) |
GET | /v1/subscriber-inbox/unread-count | Subscriber JWT | Get unread count |
GET | /v1/subscriber-inbox/:id | Subscriber JWT | Get single notification |
POST | /v1/subscriber-inbox/:id/read | Subscriber JWT | Mark as read |
POST | /v1/subscriber-inbox/read-all | Subscriber JWT | Mark all as read |
POST | /v1/subscriber-inbox/:id/archive | Subscriber JWT | Archive notification |
DELETE | /v1/subscriber-inbox/:id | Subscriber JWT | Delete notification |
GET | /v1/subscriber-inbox/preferences | Subscriber JWT | Get preferences |
PUT | /v1/subscriber-inbox/preferences | Subscriber JWT | Update preferences |
Server-Side API (Admin)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST | /v1/inbox/send | API Key | Send notification |
POST | /v1/inbox/send/batch | API Key | Send batch |
GET | /v1/inbox | API Key | List all notifications |
GET | /v1/inbox/:id | API Key | Get notification |
POST | /v1/inbox/:id/read | API Key | Mark as read |
POST | /v1/inbox/read-all | API Key | Mark all as read |
GET | /v1/inbox/unread/count | API Key | Get unread count |
POST | /v1/inbox/:id/archive | API Key | Archive |
DELETE | /v1/inbox/:id | API Key | Delete |
Notification Lifecycle
- Created — Notification sent and visible in inbox
- Read — User clicked or marked as read
- Archived — Hidden from default view
- Expired — Past expiration date (auto-archived)
- 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.