Push notifications

Send a OneSignal push notification from your backend.

Send a push notification

Send a push through OneSignal from your backend. await resolves with the delivery result — notification id, recipient count, and whether OneSignal accepted it.

Target recipients with playerIds, subscriptionIds, or includeSegments / excludeSegments. Set content with message, title, subtitle, imageUrl, data, or a saved templateId.

Server-only. Never import @bdk/native/server/onesignal (or any @bdk/native/server/* entry) into a browser bundle — it carries your OneSignal REST API key.

import { sendPushNotification } from "@bdk/native/server/onesignal";

const result = await sendPushNotification({
  oneSignalAppId: "00000000-0000-0000-0000-000000000000",
  oneSignalApiKey: "os_v2_app_...",
  message: "Your order has shipped!",
  title: "Order update",
  subscriptionIds: ["a1b2c3d4-1111-2222-3333-444455556666"]
});

if (result.sentSuccessfully) {
  console.log("Delivered", result.notificationId, "to", result.numberOfRecipients);
} else {
  console.error("OneSignal rejected the push:", result.errorMessage);
}

Input fields

The object you pass to sendPushNotification. Every field is optional, but each call needs credentials (inline or via env) and at least one targeting field.

  • message, title, subtitle — body, heading, and iOS subtitle.
  • playerIds / subscriptionIds — device targets. Prefer subscriptionIds; playerIds is the legacy key.
  • includeSegments / excludeSegments — target or exclude named OneSignal segments.
  • templateId — send a saved OneSignal template instead of inline content.
  • imageUrl — a media attachment.
  • onLoadUrl + urlParams — a launch URL. urlParams entries are appended as query parameters and passed through in data.
  • data — an arbitrary Record<string, unknown> payload.
  • iosBadgeType, iosBadgeCount — iOS badge controls.
  • oneSignalAppId, oneSignalApiKey — inline credentials.
  • targetChannel, endpoint, authorizationScheme, fetch — advanced overrides.

The OneSignalUrlParam type used by urlParams is { key: string; value: string | number | boolean }.

import type {
  SendPushNotificationInput,
  OneSignalUrlParam
} from "@bdk/native/server/onesignal";

const input: SendPushNotificationInput = {
  message: "Welcome aboard",
  title: "Hello",
  subscriptionIds: ["a1b2c3d4-1111-2222-3333-444455556666"],
  data: { onboarding: true }
};

Read the result

sendPushNotification resolves with a PushNotificationResult. Check it to confirm delivery and surface failures.

  • notificationId: string | null — the OneSignal notification id.
  • numberOfRecipients: number | null — how many recipients OneSignal reported.
  • sentSuccessfully: booleantrue only when OneSignal returned no errors.
  • errorMessage: string | null — the errors OneSignal returned, or null on success.
  • raw: unknown — the full parsed OneSignal response.

A 200 OK can still carry errors (e.g. "All included players are not subscribed"), so always check sentSuccessfully — not just the absence of a thrown error. A non-2xx status throws a BdkError with code BDK_PROVIDER_ERROR.

import { sendPushNotification } from "@bdk/native/server/onesignal";
import { BdkError } from "@bdk/native";

try {
  const result = await sendPushNotification({
    message: "Ping",
    subscriptionIds: ["a1b2c3d4-1111-2222-3333-444455556666"]
  });

  if (!result.sentSuccessfully) {
    // 2xx response but OneSignal reported errors in the body.
    console.warn("Not delivered:", result.errorMessage, result.raw);
  }
} catch (err) {
  if (err instanceof BdkError && err.code === "BDK_PROVIDER_ERROR") {
    console.error("OneSignal HTTP error:", err.details);
  } else {
    throw err;
  }
}

Set credentials

Pass your OneSignal app id and REST API key inline as oneSignalAppId / oneSignalApiKey, or set them in the environment and omit them from the call.

For the app id it reads BDK_ONESIGNAL_APP_ID, then ONESIGNAL_APP_ID; for the key, BDK_ONESIGNAL_API_KEY, then ONESIGNAL_API_KEY. Inline values win. Missing either throws a BdkError with code BDK_VALIDATION_ERROR. The Authorization scheme is picked from your key automatically — override it with authorizationScheme ("Basic" | "Key" | "Bearer") if needed.

Prefer env vars — keep secrets out of your code and rotate keys without redeploying.

// BDK_ONESIGNAL_APP_ID and BDK_ONESIGNAL_API_KEY (or ONESIGNAL_APP_ID /
// ONESIGNAL_API_KEY) are read from the environment — no credentials in code.
import { sendPushNotification } from "@bdk/native/server/onesignal";

const result = await sendPushNotification({
  message: "Server-driven push",
  includeSegments: ["Subscribed Users"]
});

Call from a backend

Drop the call into any backend route, queue worker, or cron job. Node 18+ uses the global fetch; on older runtimes pass your own via fetch. Override endpoint to point at a proxy or test server (defaults to https://onesignal.com/api/v1/notifications).

If no fetch is available and you don't pass one, the request throws a BdkError with code BDK_PROVIDER_ERROR.

import express from "express";
import { sendPushNotification } from "@bdk/native/server/onesignal";

const app = express();
app.use(express.json());

app.post("/notify", async (req, res) => {
  const result = await sendPushNotification({
    message: req.body.message,
    title: req.body.title,
    subscriptionIds: req.body.subscriptionIds
    // credentials read from env
  });

  res.status(result.sentSuccessfully ? 200 : 502).json(result);
});