> ## Documentation Index
> Fetch the complete documentation index at: https://notifyflow.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# In-App Channel

> Display persistent alerts to users inside your platform

The `IN_APP` channel stores notification payloads in the database instead of dispatching to external carriers. This gives you a fast, reliable mechanism for populating user-facing activity feeds.

## Reading and Marking Feeds

Applications read from and update the state of the `inapp_notifications` table:

* **Polling:** Query unread items on a periodic loop (e.g. every 15s) from your web components.
* **Server-Sent Events (SSE):** Establish persistent socket-like streaming channels to display instant feed increments without polling.

***

## Database Schema Structure

The underlying table layout is defined in `schema.prisma`:

```prisma theme={null}
model InAppNotification {
  id          String   @id @default(uuid())
  tenantId    String   @map("tenant_id")
  recipientId String   @map("recipient_id")
  title       String
  body        String   @db.Text
  read        Boolean  @default(false)
  createdAt   DateTime @default(now()) @map("created_at")
  readAt      DateTime? @map("read_at")
}
```

***

## Building a Notification UI

For a premium user experience, follow these design guidelines in your client-side implementation:

1. **Badges:** Use a badge (e.g. rose-600 background) displaying the unread notification count on top of a Bell icon.
2. **Smooth Dismissal:** Trigger a fast optimistic UI update, hiding the dismissed element instantly while launching the mark-as-read `POST` call in the background.
3. **Empty States:** Render a clean illustration and description (e.g., "All caught up!") when there are no unread notifications.

***

## Developer Implementation

### 1. Triggering an In-App Notification

To trigger an in-app notification for a user, call `POST /api/v1/notify` specifying `IN_APP` as the channel:

```typescript theme={null}
const response = await fetch("https://notifyflow-api.onrender.com/api/v1/notify", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-api-key": process.env.NOTIFYFLOW_API_KEY
  },
  body: JSON.stringify({
    channel: "IN_APP",
    recipient: "demo-user-id", // Identifies the recipient user in your system
    rawSubject: "New Support Ticket", // Displayed as notification title
    rawBody: "Ticket #SUP-1024 has been successfully opened.", // Notification content body
    priority: "DEFAULT"
  })
});
```

### 2. Fetching Notifications (Backend Proxy)

Always fetch notifications through your own backend proxy to avoid exposing your secret API key to the browser:

```typescript theme={null}
// Your backend route (e.g. GET /api/notifications)
export async function GET(req, res) {
  const userId = req.user.id; // Authenticated user ID in your app

  const response = await fetch(`https://notifyflow-api.onrender.com/api/v1/notify/inapp/\${userId}`, {
    method: "GET",
    headers: {
      "x-api-key": process.env.NOTIFYFLOW_API_KEY
    }
  });

  const data = await response.json();
  return res.json(data);
}
```

### 3. Marking Notifications as Read

To mark notifications as read when the user views their feed, invoke the read endpoint:

```typescript theme={null}
// Your backend route (e.g. POST /api/notifications/read)
export async function POST(req, res) {
  const userId = req.user.id;

  const response = await fetch(`https://notifyflow-api.onrender.com/api/v1/notify/inapp/\${userId}/read`, {
    method: "POST",
    headers: {
      "x-api-key": process.env.NOTIFYFLOW_API_KEY
    }
  });

  return res.json({ success: true });
}
```
