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
MudbaseWebPushhelper, 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:
- Get a device token in your app (client side).
- Register the token with your project -
POST /messaging/devices. - 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:
// 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 - theMudbaseWebPushSDK 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
POST /api/messaging/projects/{projectId}/messaging/devices
Authorization: Bearer {token}
Content-Type: application/jsonPOST /api/messaging/projects/{projectId}/messaging/devices
Authorization: Bearer {token}
Content-Type: application/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
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
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
{
"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
POST /api/messaging/projects/{projectId}/messaging/push
Authorization: Bearer {token}
Content-Type: application/jsonPOST /api/messaging/projects/{projectId}/messaging/push
Authorization: Bearer {token}
Content-Type: application/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
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
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
{
"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: falsewith 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:
- Enable native Web Push on the project once -
PATCH /messaging/web-push-config. This provisions a VAPID keypair. - Subscribe the browser - fetch the project's public key, ask the browser to subscribe, and register the subscription with Mudbase. The
MudbaseWebPushSDK helper does all of this in one call. - Send a push to your subscribers - the same
POST /messaging/pushendpoint, 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
PATCH /api/messaging/projects/{projectId}/messaging/web-push-config
Authorization: Bearer {token}
Content-Type: application/jsonPATCH /api/messaging/projects/{projectId}/messaging/web-push-config
Authorization: Bearer {token}
Content-Type: application/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
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
{
"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)
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:
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.
// 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:
POST /api/messaging/projects/{projectId}/messaging/web-push/subscriptions
Authorization: Bearer {token}
Content-Type: application/jsonPOST /api/messaging/projects/{projectId}/messaging/web-push/subscriptions
Authorization: Bearer {token}
Content-Type: application/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
POST /api/messaging/projects/{projectId}/messaging/push
Authorization: Bearer {token}
Content-Type: application/jsonPOST /api/messaging/projects/{projectId}/messaging/push
Authorization: Bearer {token}
Content-Type: application/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
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
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:
{
"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):
GET /api/messaging/projects/{projectId}/messaging/web-push/subscriptions
Authorization: Bearer {token}GET /api/messaging/projects/{projectId}/messaging/web-push/subscriptions
Authorization: Bearer {token}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):
DELETE /api/messaging/projects/{projectId}/messaging/web-push/subscriptions
Authorization: Bearer {token}
Content-Type: application/jsonDELETE /api/messaging/projects/{projectId}/messaging/web-push/subscriptions
Authorization: Bearer {token}
Content-Type: application/json{ "endpoint": "https://push-service.example.com/subscribe/abc123" }{ "endpoint": "https://push-service.example.com/subscribe/abc123" }await messaging.removeWebPushSubscription({
projectId,
webPushUnsubscribeRequest: { endpoint: subscription.endpoint },
});await messaging.removeWebPushSubscription({
projectId,
webPushUnsubscribeRequest: { endpoint: subscription.endpoint },
});Managing tokens
List registered tokens
GET /api/messaging/projects/{projectId}/messaging/devices
Authorization: Bearer {token}GET /api/messaging/projects/{projectId}/messaging/devices
Authorization: Bearer {token}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:
DELETE /api/messaging/projects/{projectId}/messaging/devices
Authorization: Bearer {token}
Content-Type: application/jsonDELETE /api/messaging/projects/{projectId}/messaging/devices
Authorization: Bearer {token}
Content-Type: application/json{ "token": "fMEGV8example-device-push-token-string9xY" }{ "token": "fMEGV8example-device-push-token-string9xY" }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. Sendclear: trueon 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.