Guides

Push notifications

Send push notifications to your users' devices with the REST API or the official SDKs. For the full list of paths and schemas, see the API reference or OpenAPI.

Push works out of the box - Mudbase manages the push credentials for you, so there is nothing to configure to start sending. Bringing your own push credentials is an optional advanced step covered at the end.

Two ways to deliver push

Mudbase gives you two first-party push channels, and a single send can target either or both:

  • Device tokens - your app obtains a push token from its platform's push client (mobile, or a web app that already has one) and registers it. Best for iOS / Android apps. Covered in The device-token flow below.
  • Native Web Push (VAPID) - deliver browser push directly with the built-in MudbaseWebPush helper, with no per-project push provider account required. Best for web apps. Covered in Native Web Push in the browser below.

Both channels deliver through the same send endpoint, POST /messaging/push.

The device-token flow

Sending a push to a registered device token takes three steps:

  1. Get a device token in your app (client side).
  2. Register the token with your project - POST /messaging/devices.
  3. Send a push to that token - POST /messaging/push.

The send endpoint only delivers to tokens that are registered to the project. Any token you pass to the send endpoint that has not been registered is dropped - so step 2 is required before step 3, not optional.

Step 1 - Get a device token in your app

A device token (also called a push token) is a string your app obtains from the device's push service. Your app asks the user for notification permission, then asks the platform's push client for a token. That token string is what you hand to Mudbase in step 2 - Mudbase treats it as opaque.

Requesting permission is standard and needs no library:

JavaScript
// Web: ask the user for notification permission (browser Push API - no library needed).
const permission = await Notification.requestPermission();
if (permission !== "granted") {
  throw new Error("Notification permission was not granted");
}

// Get a device push token from your app's push client and keep the string.
// Mudbase just needs the exact token string your device's push service issued.
// See "Getting the token" below.
const deviceToken = await getDevicePushToken();
// Web: ask the user for notification permission (browser Push API - no library needed).
const permission = await Notification.requestPermission();
if (permission !== "granted") {
  throw new Error("Notification permission was not granted");
}

// Get a device push token from your app's push client and keep the string.
// Mudbase just needs the exact token string your device's push service issued.
// See "Getting the token" below.
const deviceToken = await getDevicePushToken();

On mobile, the shape is the same: request permission, then read the token your platform's push registration returns (iOS / Android), and pass that string to Mudbase.

Getting the token. For the device-token path, Mudbase does not mint the device token for you - you obtain it with your app platform's own push client and pass the resulting string to registerDeviceToken. The register and send steps below are fully first-party. If you are building a web app, use Native Web Push instead - the MudbaseWebPush SDK helper handles the whole browser subscribe-and-register flow end to end.

Step 2 - Register the token

Register the token string with your project so it becomes eligible to receive push. Registration is idempotent - re-registering an existing token just refreshes it, so it is safe to call on every app launch.

Request

HTTP
POST /api/messaging/projects/{projectId}/messaging/devices
Authorization: Bearer {token}
Content-Type: application/json
POST /api/messaging/projects/{projectId}/messaging/devices
Authorization: Bearer {token}
Content-Type: application/json
JSON
{
  "token": "fMEGV8example-device-push-token-string9xY",
  "platform": "web"
}
{
  "token": "fMEGV8example-device-push-token-string9xY",
  "platform": "web"
}

platform is optional and one of ios, android, web, or unknown (the default).

cURL

Shell
curl -X POST https://cloud.mudbase.dev/api/messaging/projects/PROJECT_ID/messaging/devices \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"token":"fMEGV8example-device-push-token-string9xY","platform":"web"}'
curl -X POST https://cloud.mudbase.dev/api/messaging/projects/PROJECT_ID/messaging/devices \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"token":"fMEGV8example-device-push-token-string9xY","platform":"web"}'

SDK

TypeScript
import { Configuration, MessagingApi } from "mudbase-sdk";

const config = new Configuration({
  basePath: "https://cloud.mudbase.dev",
  baseOptions: { headers: { "X-API-Key": process.env.MUDBASE_API_KEY } },
});
const messaging = new MessagingApi(config);

await messaging.registerDeviceToken({
  projectId,
  deviceRegisterRequest: { token: deviceToken, platform: "web" },
});
import { Configuration, MessagingApi } from "mudbase-sdk";

const config = new Configuration({
  basePath: "https://cloud.mudbase.dev",
  baseOptions: { headers: { "X-API-Key": process.env.MUDBASE_API_KEY } },
});
const messaging = new MessagingApi(config);

await messaging.registerDeviceToken({
  projectId,
  deviceRegisterRequest: { token: deviceToken, platform: "web" },
});

Response

JSON
{
  "success": true,
  "data": {
    "token": "fMEGV8example-device-push-token-string9xY",
    "platform": "web",
    "lastSeenAt": "2024-01-15T10:00:00.000Z"
  }
}
{
  "success": true,
  "data": {
    "token": "fMEGV8example-device-push-token-string9xY",
    "platform": "web",
    "lastSeenAt": "2024-01-15T10:00:00.000Z"
  }
}

Step 3 - Send a push

Send to one or more registered tokens. Tokens that are not registered to the project are silently dropped.

Request

HTTP
POST /api/messaging/projects/{projectId}/messaging/push
Authorization: Bearer {token}
Content-Type: application/json
POST /api/messaging/projects/{projectId}/messaging/push
Authorization: Bearer {token}
Content-Type: application/json
JSON
{
  "tokens": ["fMEGV8example-device-push-token-string9xY"],
  "title": "New message",
  "body": "You have a new message",
  "data": { "conversationId": "abc123" }
}
{
  "tokens": ["fMEGV8example-device-push-token-string9xY"],
  "title": "New message",
  "body": "You have a new message",
  "data": { "conversationId": "abc123" }
}

cURL

Shell
curl -X POST https://cloud.mudbase.dev/api/messaging/projects/PROJECT_ID/messaging/push \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tokens":["fMEGV8example-device-push-token-string9xY"],"title":"New message","body":"You have a new message"}'
curl -X POST https://cloud.mudbase.dev/api/messaging/projects/PROJECT_ID/messaging/push \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tokens":["fMEGV8example-device-push-token-string9xY"],"title":"New message","body":"You have a new message"}'

SDK

TypeScript
await messaging.sendPushNotification({
  projectId,
  pushNotificationRequest: {
    tokens: [deviceToken],
    title: "New message",
    body: "You have a new message",
    data: { conversationId: "abc123" },
  },
});
await messaging.sendPushNotification({
  projectId,
  pushNotificationRequest: {
    tokens: [deviceToken],
    title: "New message",
    body: "You have a new message",
    data: { conversationId: "abc123" },
  },
});

Response

JSON
{
  "success": true,
  "data": {
    "type": "push",
    "status": "sent",
    "recipients": 1,
    "sentAt": "2024-01-15T10:00:00.000Z"
  }
}
{
  "success": true,
  "data": {
    "type": "push",
    "status": "sent",
    "recipients": 1,
    "sentAt": "2024-01-15T10:00:00.000Z"
  }
}

If none of the tokens are registered, the send returns success: false with a message telling you to register a device token first. Register (step 2) before sending.

Native Web Push in the browser (VAPID)

For web apps, Mudbase delivers push natively in the browser using the Web Push standard (VAPID) - no per-project push provider account is required. The flow is:

  1. Enable native Web Push on the project once - PATCH /messaging/web-push-config. This provisions a VAPID keypair.
  2. Subscribe the browser - fetch the project's public key, ask the browser to subscribe, and register the subscription with Mudbase. The MudbaseWebPush SDK helper does all of this in one call.
  3. Send a push to your subscribers - the same POST /messaging/push endpoint, targeting Web Push subscribers by endpoint, userId, or a broadcast.

Step 1 - Enable native Web Push on the project

Turn native Web Push on for the project. This is a one-time setup (do it in the console or via the API). Enabling provisions the VAPID keypair automatically.

Request

HTTP
PATCH /api/messaging/projects/{projectId}/messaging/web-push-config
Authorization: Bearer {token}
Content-Type: application/json
PATCH /api/messaging/projects/{projectId}/messaging/web-push-config
Authorization: Bearer {token}
Content-Type: application/json
JSON
{ "enabled": true, "subject": "mailto:push@yourapp.com" }
{ "enabled": true, "subject": "mailto:push@yourapp.com" }

subject is the RFC 8292 contact - a mailto: address or an https URL. To rotate the keypair later, send { "rotateKeys": true } (this invalidates existing subscriptions - clients must re-subscribe).

cURL

Shell
curl -X PATCH https://cloud.mudbase.dev/api/messaging/projects/PROJECT_ID/messaging/web-push-config \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled":true,"subject":"mailto:push@yourapp.com"}'
curl -X PATCH https://cloud.mudbase.dev/api/messaging/projects/PROJECT_ID/messaging/web-push-config \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled":true,"subject":"mailto:push@yourapp.com"}'

Response

JSON
{
  "success": true,
  "data": {
    "enabled": true,
    "hasKeys": true,
    "publicKey": "BJ8...application-server-key...9xY",
    "vapidSubject": "mailto:push@yourapp.com",
    "generatedAt": "2024-01-15T10:00:00.000Z"
  }
}
{
  "success": true,
  "data": {
    "enabled": true,
    "hasKeys": true,
    "publicKey": "BJ8...application-server-key...9xY",
    "vapidSubject": "mailto:push@yourapp.com",
    "generatedAt": "2024-01-15T10:00:00.000Z"
  }
}

Step 2 - Subscribe the browser

Your web app needs a service worker registered (this is what receives and shows the push). Once it is, the SDK helper handles the rest - it fetches the public key, requests notification permission, subscribes via the browser's Push API, and registers the subscription with Mudbase.

SDK (recommended)

TypeScript
import { Configuration, MudbaseWebPush } from "mudbase-sdk";

const config = new Configuration({
  basePath: "https://cloud.mudbase.dev",
  accessToken: userAccessToken, // or apiKey for programmatic access
});

const webPush = new MudbaseWebPush({ projectId, configuration: config });

// One call: fetch key -> request permission -> subscribe -> register with Mudbase.
const subscription = await webPush.subscribe({ userId: currentUser.id });
// { endpoint, userId, lastSeenAt }
import { Configuration, MudbaseWebPush } from "mudbase-sdk";

const config = new Configuration({
  basePath: "https://cloud.mudbase.dev",
  accessToken: userAccessToken, // or apiKey for programmatic access
});

const webPush = new MudbaseWebPush({ projectId, configuration: config });

// One call: fetch key -> request permission -> subscribe -> register with Mudbase.
const subscription = await webPush.subscribe({ userId: currentUser.id });
// { endpoint, userId, lastSeenAt }

The helper awaits navigator.serviceWorker.ready, so register your service worker first (e.g. navigator.serviceWorker.register("/sw.js")). To use a specific registration, pass it as serviceWorkerRegistration.

On logout, tear the subscription down (browser + server) in one call:

TypeScript
await webPush.unsubscribe();
await webPush.unsubscribe();

Doing it manually (REST)

If you would rather own the browser calls, fetch the public key (no auth needed) and register the resulting subscription yourself.

TypeScript
// 1. Fetch the project's public application-server key (public route, no auth).
const res = await fetch(
  `https://cloud.mudbase.dev/api/messaging/projects/${projectId}/messaging/web-push/public-key`,
);
const { data } = await res.json(); // { enabled, publicKey }

// 2. Subscribe the browser with that key.
const registration = await navigator.serviceWorker.ready;
const sub = await registration.pushManager.subscribe({
  userVisibleOnly: true,
  applicationServerKey: data.publicKey, // base64url; decode to Uint8Array in older browsers
});

// 3. Register the subscription with Mudbase.
await fetch(
  `https://cloud.mudbase.dev/api/messaging/projects/${projectId}/messaging/web-push/subscriptions`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${userAccessToken}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ subscription: sub.toJSON(), userId: currentUser.id }),
  },
);
// 1. Fetch the project's public application-server key (public route, no auth).
const res = await fetch(
  `https://cloud.mudbase.dev/api/messaging/projects/${projectId}/messaging/web-push/public-key`,
);
const { data } = await res.json(); // { enabled, publicKey }

// 2. Subscribe the browser with that key.
const registration = await navigator.serviceWorker.ready;
const sub = await registration.pushManager.subscribe({
  userVisibleOnly: true,
  applicationServerKey: data.publicKey, // base64url; decode to Uint8Array in older browsers
});

// 3. Register the subscription with Mudbase.
await fetch(
  `https://cloud.mudbase.dev/api/messaging/projects/${projectId}/messaging/web-push/subscriptions`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${userAccessToken}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ subscription: sub.toJSON(), userId: currentUser.id }),
  },
);

The register request body is the browser PushSubscription (endpoint plus the p256dh / auth keys) with an optional userId / deviceId:

HTTP
POST /api/messaging/projects/{projectId}/messaging/web-push/subscriptions
Authorization: Bearer {token}
Content-Type: application/json
POST /api/messaging/projects/{projectId}/messaging/web-push/subscriptions
Authorization: Bearer {token}
Content-Type: application/json
JSON
{
  "subscription": {
    "endpoint": "https://push-service.example.com/subscribe/abc123",
    "keys": { "p256dh": "BE...", "auth": "..." }
  },
  "userId": "user_123"
}
{
  "subscription": {
    "endpoint": "https://push-service.example.com/subscribe/abc123",
    "keys": { "p256dh": "BE...", "auth": "..." }
  },
  "userId": "user_123"
}

Registration is idempotent - re-registering the same endpoint refreshes it, so it is safe to call on every page load.

Step 3 - Send to your Web Push subscribers

Send with the same POST /messaging/push endpoint. For native Web Push, target subscribers by endpoints, by userIds, or set webPushBroadcast: true to reach every subscriber in the project. title and body are required; provide at least one target.

Request

HTTP
POST /api/messaging/projects/{projectId}/messaging/push
Authorization: Bearer {token}
Content-Type: application/json
POST /api/messaging/projects/{projectId}/messaging/push
Authorization: Bearer {token}
Content-Type: application/json
JSON
{
  "webPushBroadcast": true,
  "title": "New message",
  "body": "You have a new message",
  "data": { "conversationId": "abc123" }
}
{
  "webPushBroadcast": true,
  "title": "New message",
  "body": "You have a new message",
  "data": { "conversationId": "abc123" }
}

cURL

Shell
curl -X POST https://cloud.mudbase.dev/api/messaging/projects/PROJECT_ID/messaging/push \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"userIds":["user_123"],"title":"New message","body":"You have a new message"}'
curl -X POST https://cloud.mudbase.dev/api/messaging/projects/PROJECT_ID/messaging/push \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"userIds":["user_123"],"title":"New message","body":"You have a new message"}'

SDK

TypeScript
import { Configuration, MessagingApi } from "mudbase-sdk";

const messaging = new MessagingApi(config);

await messaging.sendPushNotification({
  projectId,
  pushNotificationRequest: {
    userIds: ["user_123"],       // or endpoints: [...], or webPushBroadcast: true
    title: "New message",
    body: "You have a new message",
    data: { conversationId: "abc123" },
  },
});
import { Configuration, MessagingApi } from "mudbase-sdk";

const messaging = new MessagingApi(config);

await messaging.sendPushNotification({
  projectId,
  pushNotificationRequest: {
    userIds: ["user_123"],       // or endpoints: [...], or webPushBroadcast: true
    title: "New message",
    body: "You have a new message",
    data: { conversationId: "abc123" },
  },
});

Response

The send reports per channel - channels.webPush for native Web Push and channels.fcm for device tokens; either is null when that channel had no targets:

JSON
{
  "success": true,
  "data": {
    "success": true,
    "messageId": "65a1b2c3d4e5f6789012345c",
    "successCount": 2,
    "failureCount": 0,
    "channels": {
      "fcm": null,
      "webPush": { "successCount": 2, "failureCount": 0, "pruned": 0 }
    }
  }
}
{
  "success": true,
  "data": {
    "success": true,
    "messageId": "65a1b2c3d4e5f6789012345c",
    "successCount": 2,
    "failureCount": 0,
    "channels": {
      "fcm": null,
      "webPush": { "successCount": 2, "failureCount": 0, "pruned": 0 }
    }
  }
}

pruned counts subscriptions the push service reported as gone; Mudbase removes those automatically, so your subscriber list stays clean.

Managing Web Push subscriptions

List subscriptions (keys are never returned):

HTTP
GET /api/messaging/projects/{projectId}/messaging/web-push/subscriptions
Authorization: Bearer {token}
GET /api/messaging/projects/{projectId}/messaging/web-push/subscriptions
Authorization: Bearer {token}
TypeScript
const { data } = await messaging.listWebPushSubscriptions({ projectId });
const { data } = await messaging.listWebPushSubscriptions({ projectId });

Unsubscribe by endpoint (on logout, or when the SDK helper is not in use):

HTTP
DELETE /api/messaging/projects/{projectId}/messaging/web-push/subscriptions
Authorization: Bearer {token}
Content-Type: application/json
DELETE /api/messaging/projects/{projectId}/messaging/web-push/subscriptions
Authorization: Bearer {token}
Content-Type: application/json
JSON
{ "endpoint": "https://push-service.example.com/subscribe/abc123" }
{ "endpoint": "https://push-service.example.com/subscribe/abc123" }
TypeScript
await messaging.removeWebPushSubscription({
  projectId,
  webPushUnsubscribeRequest: { endpoint: subscription.endpoint },
});
await messaging.removeWebPushSubscription({
  projectId,
  webPushUnsubscribeRequest: { endpoint: subscription.endpoint },
});

Managing tokens

List registered tokens

HTTP
GET /api/messaging/projects/{projectId}/messaging/devices
Authorization: Bearer {token}
GET /api/messaging/projects/{projectId}/messaging/devices
Authorization: Bearer {token}
TypeScript
const { data } = await messaging.listDeviceTokens({ projectId });
const { data } = await messaging.listDeviceTokens({ projectId });

Unregister a token on logout or when a token rotates, so the send endpoint stops delivering to it:

HTTP
DELETE /api/messaging/projects/{projectId}/messaging/devices
Authorization: Bearer {token}
Content-Type: application/json
DELETE /api/messaging/projects/{projectId}/messaging/devices
Authorization: Bearer {token}
Content-Type: application/json
JSON
{ "token": "fMEGV8example-device-push-token-string9xY" }
{ "token": "fMEGV8example-device-push-token-string9xY" }
TypeScript
await messaging.unregisterDeviceToken({
  projectId,
  deviceUnregisterRequest: { token: deviceToken },
});
await messaging.unregisterDeviceToken({
  projectId,
  deviceUnregisterRequest: { token: deviceToken },
});

Each project has a cap on how many tokens it can keep registered. When the cap is reached, the least-recently-seen tokens are evicted automatically to make room, so a register-on-launch call never fails.

Advanced (optional) - Bring your own push credentials

By default, push is delivered with platform-managed credentials and needs no setup. If you would rather deliver push from your own push provider account (your own sender identity and quotas), you can upload your own push provider's service account JSON per project.

  • In the console: Messaging -> Push credentials (see the console Messaging guide).
  • Via the API: PATCH /api/messaging/projects/{projectId}/messaging/push-config - see the API reference. Send clear: true on that endpoint to remove your credentials and revert to the platform-managed default.

This is entirely optional - projects that leave it unset keep sending push with the platform-managed credentials.

Chat with us