Expo Push (Classic)

Create indie notification inbox

Fetch a subscriber's notifications with getIndieNotificationInbox to build your own inbox screen.

Premium has no inbox

On Premium, every inbox call answers 201 with an explanation, so the SDK shows an empty inbox and an unread count of 0. See what each plan includes.

Get notifications

getIndieNotificationInbox returns a subscriber's notifications, newest first: the pushes sent to that subId plus your mass pushes sent after it registered. They're kept for 365 days.

import React, { useState, useEffect } from 'react';
import { getIndieNotificationInbox } from 'native-notify';

export default function NotificationInbox() {
    const [data, setData] = useState([]);
    const [takeNumber, setTakeNumber] = useState(10);
    const [skipNumber, setSkipNumber] = useState(0);

    const fetchNotifications = async () => {
        try {
            const notifications = await getIndieNotificationInbox(
                "unique-user-id",
                yourAppId,
                'yourAppToken',
                takeNumber,
                skipNumber
            );
            console.log("notifications: ", notifications);
            setData(notifications);
        } catch (error) {
            console.error("Error fetching notifications: ", error);
        }
    };

    useEffect(() => {
      fetchNotifications();
    }, []);

    return (
      ... // create an Indie Notification Inbox using getIndieNotificationInbox data
    )
}
ArgumentRequiredNotes
subIdyesThe id you registered with registerIndieID.
appId, appTokennoYour app's id and token from your Native Notify dashboard. Default to NativeNotify.init().
takenoRows per page. Defaults to 20 in v5 and later. v4 and raw REST calls default to 10.
skipnoRows to skip. Defaults to 0.

It resolves with an array of rows:

[
  {
    "notification_id": 12345678,
    "date": "9-17-2026 7:24PM",
    "title": "New comment",
    "message": "Someone commented on your post",
    "pushData": "{\"postId\":\"a1b2c3\"}",
    "read": true
  }
]

pushData is the JSON string you sent: JSON.parse(row.pushData). A plain fetch marks every notification of the subscriber read before it lists them, so each row comes back read: true. For the real state, use per-notification read state. A failed request (a 401, a network error) rejects, so keep the try / catch.

Exact pagination

getIndieNotificationInboxPage also returns the subscriber's own row total, from the X-Total-Count response header, so "load more" is exact. getIndieNotificationInbox returns the rows alone.

import { getIndieNotificationInboxPage } from 'native-notify';

const { rows, total } = await getIndieNotificationInboxPage(
  "unique-user-id",
  yourAppId,
  'yourAppToken',
  20, // take
  0   // skip
);

console.log(rows.length, "of", total); // total is null when the server doesn't send the header

Per-notification read state

Needs native-notify v5.2 or later. Pass { perNotification: true } as the sixth argument of the page function. Each row keeps its own read flag, and the server stops marking the inbox read on fetch. Mark a row read when the user opens it:

import { getIndieNotificationInboxPage, markIndieNotificationRead } from 'native-notify';

const { rows, total } = await getIndieNotificationInboxPage(
  "unique-user-id",
  yourAppId,
  'yourAppToken',
  20, // take
  0,  // skip
  { perNotification: true }
);

rows[0].read; // this subscriber's own read state

// Mark ONE row read when it is opened (best-effort — resolves false, never throws).
// Pass the ids unless you set them once with NativeNotify.init():
await markIndieNotificationRead(rows[0].notification_id, "unique-user-id", yourAppId, 'yourAppToken');

markIndieNotificationRead(notificationId, subId, appId?, appToken?) resolves true when the server accepted the mark and false on any failure. Without a notificationId it resolves false and sends nothing, because the id-less endpoint form marks the whole inbox read.

Unlike mass, read state here is per subId, so it works on simulators, in Expo Go and on the web. The prebuilt components and useNotificationInbox() take the same option as perNotificationRead.

Call the endpoint directly

GET https://app.nativenotify.com/api/indie/notification/inbox/{subId}/{appId}/{appToken}?take=10&skip=0
QueryDefaultNotes
take10Rows per page.
skip0Rows to skip.
perNotification—true lists each row's real read state and marks nothing. Without it, the call marks every notification of the subscriber read first.

Mark read:

POST https://app.nativenotify.com/api/indie/notification/inbox/read
{ "appId": 12345, "appToken": "yourAppToken", "subId": "unique-user-id", "notificationId": 12345678 }

notificationId is optional. Without it, everything for the subscriber is marked read.

StatusMeaning
201The array of rows above. [] means nothing has reached that subId: compare it with the id you registered and send to. A mark-read call answers 201 with Notifications Read Updated.
201 with textPremium: nothing is listed or marked, so the SDK returns []. Check that the body is an array before you use it.
400A mark-read call without a subId.
401The appId and appToken pair doesn't match an app.

Premium accounts get this text instead of a list:

Your current Native Notify membership cannot access notification inbox features. You must upgrade to a higher membership to access notification inbox features.

Responses are never cached.