Messages
Apps can send push notifications and emails to users through a durable message queue. Messages are enqueued via the notify() and email() callbacks in server route handlers and agent tools, then delivered asynchronously by a background dispatcher with retry and dead-letter handling.
Message Lifecycle
pending → dispatched → delivered (success)
pending → dispatched → pending (failure, will retry)
pending → dispatched → dead (max retries exceeded)
dead/failed → pending (manual retry via API)
Channels
| Channel | Recipient | Delivery Method |
|---|---|---|
push | Informer username | FCM to all registered devices (Informer GO) |
email | Email address | Tenant mail transport (SMTP, Gmail API, Microsoft Graph) |
Push notifications include the app's ID automatically — tapping a notification in Informer GO opens the app, optionally at a specific sub-page via the path field.
GET /api/apps/{id}/messages
List messages for an app with optional filters and cursor-based pagination.
Authentication: Required
Permissions Required: Member+ role (write permission)
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | App UUID or natural ID |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
channel | string | — | Filter by channel: push or email |
status | string | — | Filter by status: pending, dispatched, delivered, failed, dead |
recipient | string | — | Filter by recipient (exact match) |
limit | number | 100 | Max results (1–500) |
before | ISO date | — | Cursor: return messages created before this timestamp |
Response:
{
"messages": [
{
"id": "uuid",
"channel": "push",
"recipient": "jane",
"payload": {
"title": "Order Shipped",
"body": "Your order #1234 has shipped!",
"path": "/orders/1234"
},
"status": "delivered",
"attempts": 1,
"maxAttempts": 3,
"error": null,
"createdAt": "2026-04-12T14:00:00.000Z",
"processedAt": "2026-04-12T14:00:01.500Z"
}
],
"summary": [
{ "status": "delivered", "count": 42 },
{ "status": "failed", "count": 3 },
{ "status": "dead", "count": 1 }
]
}
The summary provides status counts for the last 30 days (useful for dashboard indicators).
Cursor Pagination:
Use the createdAt of the last message as the before parameter:
// First page
const page1 = await fetch('/api/apps/{id}/messages?limit=50');
// Next page
const lastDate = page1.messages[page1.messages.length - 1].createdAt;
const page2 = await fetch(`/api/apps/{id}/messages?limit=50&before=${lastDate}`);
GET /api/apps/{id}/messages/{messageId}
Get a single message by ID.
Authentication: Required
Permissions Required: Member+ role (write permission)
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | App UUID or natural ID |
messageId | string | Message UUID |
Response: Single message object (same shape as items in the list response).
Error Responses:
404 Not Found— Message does not exist or does not belong to this app
POST /api/apps/{id}/messages/{messageId}/_retry
Retry a failed or dead message. Resets the message to pending status with zero attempts so the dispatcher will pick it up again.
Authentication: Required
Permissions Required: Member+ role (write permission)
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | App UUID or natural ID |
messageId | string | Message UUID |
Response: The updated message object with status: "pending".
Error Responses:
404 Not Found— Message does not exist409 Conflict— Message is not in a retryable state (e.g., alreadypendingordelivered)
Sending Messages from App Code
Messages are sent from server route handlers and agent tools using the notify() and email() callbacks. See the handler documentation for full API details.
Quick Reference
// Push notification
const { id } = await notify('username', {
title: 'Alert',
body: 'Something happened',
path: '/details/123' // optional deep link
});
// Email
const { id } = await email('user@example.com', {
subject: 'Report Ready',
html: '<p>Your report is attached.</p>',
from: 'noreply@example.com' // optional
});
// Bulk push
const { ids, queued } = await notify([
{ username: 'alice', title: 'Update', body: '...' },
{ username: 'bob', title: 'Update', body: '...' },
]);
// Bulk email
const { ids, queued } = await email([
{ to: 'alice@example.com', subject: 'Update', html: '...' },
{ to: 'bob@example.com', subject: 'Update', html: '...' },
]);
HAL Relations
| Relation | Description |
|---|---|
inf:app-messages | Link to the app's message list |
inf:app-message | Link to a single message |
inf:app-message-retry | Retry a failed/dead message |