# Serverless examples

These examples send a notification with the [JavaScript SDK](https://pushgeni.us/docs/api.md) from the platforms most apps already run on. Each one follows the same three rules:

- **The REST API key stays in the platform’s secret store,** never in code or in your app. Find it, and your app ID, in the dashboard under Settings.
- **Users are targeted by `external_id`,** the ID your app passed to `BigBrain.login`. If you log users in with Supabase or Firebase Auth, use their user ID.
- **Each send has an `idempotency_key` built from the event,** such as the order ID. Webhooks and triggers can run more than once, and PushGenius sends at most one notification per key, so a retry never notifies anyone twice.

## Supabase Edge Functions

Notify a customer when their order ships, using a database webhook that calls an Edge Function each time a row in `orders` changes. Create the function:

```sh
supabase functions new order-shipped
```

Then replace `supabase/functions/order-shipped/index.ts` with:

```js
import { BigBrain } from "npm:@pushgenius/javascript@0.1";

const bigBrain = new BigBrain({
  appId: Deno.env.get("PUSHGENIUS_APP_ID")!,
  apiKey: Deno.env.get("PUSHGENIUS_API_KEY")!,
});

// Called by a database webhook on UPDATE of public.orders.
// The body is { type, table, record, old_record }.
Deno.serve(async (req) => {
  const { record, old_record } = await req.json();
  const justShipped = record.status === "shipped" && old_record?.status !== "shipped";
  if (!justShipped) return new Response("skipped");

  await bigBrain.notifications.create({
    headings: { en: "Your order shipped" },
    contents: { en: `Order #${record.id} is on its way.` },
    data: { order_id: String(record.id) },
    include_aliases: { external_id: [record.user_id] },
    // Webhooks can be retried; with the same key, the user still gets one notification.
    idempotency_key: `order-shipped-${record.id}`,
  });
  return new Response("sent");
});
```

Save your keys as secrets and deploy:

```sh
supabase secrets set PUSHGENIUS_APP_ID=YOUR_APP_ID PUSHGENIUS_API_KEY=YOUR_REST_API_KEY
supabase functions deploy order-shipped
```

In the Supabase dashboard, open **Database → Webhooks** and create a webhook on the `orders` table for **Update** events. Choose **Supabase Edge Functions** as the type, pick `order-shipped`, and add the auth header with your service key. Edge Functions reject calls without a valid token, so strangers can’t trigger sends.

## AWS Lambda

A handler you can invoke from your API, a queue, or Step Functions. Save it as `index.mjs`:

```js
import { BigBrain } from "@pushgenius/javascript";

// Created once per Lambda container and reused across invocations.
const bigBrain = new BigBrain({
  appId: process.env.PUSHGENIUS_APP_ID,
  apiKey: process.env.PUSHGENIUS_API_KEY,
});

// Invoke with { "userId": "user-123", "orderId": "A-1001" }.
export const handler = async (event) => {
  const { id, errors } = await bigBrain.notifications.create({
    headings: { en: "Your order shipped" },
    contents: { en: `Order ${event.orderId} is on its way.` },
    data: { order_id: event.orderId },
    include_aliases: { external_id: [event.userId] },
    // Lambda retries failed async invocations; with the same key, the user gets one.
    idempotency_key: `order-shipped-${event.orderId}`,
  });
  return { notificationId: id, errors };
};
```

The SDK has no dependencies, so the zip is about 25 KB. Package and create the function on the Node.js 22 runtime:

```sh
npm install @pushgenius/javascript
zip -r function.zip index.mjs node_modules
aws lambda create-function --function-name order-shipped \
  --runtime nodejs22.x --handler index.handler --zip-file fileb://function.zip \
  --role arn:aws:iam::ACCOUNT_ID:role/YOUR_LAMBDA_ROLE --timeout 15 \
  --environment "Variables={PUSHGENIUS_APP_ID=YOUR_APP_ID,PUSHGENIUS_API_KEY=YOUR_REST_API_KEY}"
```

Raise the timeout from Lambda’s default of 3 seconds, as above, so the SDK has time to retry a slow request. Anyone who can view the function in the AWS console can read its environment variables. To keep the key out of view, store it in Secrets Manager and read it when the container starts.

## Cloud Functions for Firebase

Notify the recipient of each new chat message by triggering on new Firestore documents. In `functions/package.json`, set `"type": "module"` (the SDK is an ES module) and `"engines": { "node": "22" }`. Then install the SDK:

```sh
cd functions && npm install @pushgenius/javascript
```

In `functions/index.js`:

```js
import { onDocumentCreated } from "firebase-functions/v2/firestore";
import { defineSecret, defineString } from "firebase-functions/params";
import { BigBrain } from "@pushgenius/javascript";

const appId = defineString("PUSHGENIUS_APP_ID");
const apiKey = defineSecret("PUSHGENIUS_API_KEY");

// Runs for each new message in a chat and notifies the recipient.
export const notifyRecipient = onDocumentCreated(
  { document: "chats/{chatId}/messages/{messageId}", secrets: [apiKey] },
  async (event) => {
    const message = event.data?.data();
    if (!message) return;

    // Secrets are only readable while the function runs, so create the client here.
    const bigBrain = new BigBrain({ appId: appId.value(), apiKey: apiKey.value() });
    await bigBrain.notifications.create({
      headings: { en: message.senderName },
      contents: { en: message.text },
      data: { chat_id: event.params.chatId },
      include_aliases: { external_id: [message.recipientId] },
      // event.id is the same if Firebase delivers this event twice.
      idempotency_key: event.id,
    });
  },
);
```

Put `PUSHGENIUS_APP_ID=YOUR_APP_ID` in `functions/.env`, then save the key as a secret and deploy:

```sh
firebase functions:secrets:set PUSHGENIUS_API_KEY
firebase deploy --only functions
```

Secrets and requests to services outside Google need the Blaze plan. To try it in the emulator, put `PUSHGENIUS_API_KEY=YOUR_REST_API_KEY` in `functions/.secret.local` and run `firebase emulators:start --only functions,firestore`.

## Cloudflare Workers

Send a daily summary to everyone on a cron schedule. The SDK uses only web-standard APIs, so it needs no `nodejs_compat` flag. Use version 0.1.1 or later. Install it in your Worker project:

```sh
npm install @pushgenius/javascript
```

In `src/index.js`:

```js
import { BigBrain } from "@pushgenius/javascript";

export default {
  // Runs on the cron schedule in wrangler.jsonc.
  async scheduled(controller, env) {
    const bigBrain = new BigBrain({
      appId: env.PUSHGENIUS_APP_ID,
      apiKey: env.PUSHGENIUS_API_KEY,
    });
    await bigBrain.notifications.create({
      headings: { en: "Your daily summary is ready" },
      contents: { en: "Tap to see what happened today." },
      included_segments: ["Subscribed Users"],
      // One key per scheduled time, so the same run never sends twice.
      idempotency_key: `daily-summary-${controller.scheduledTime}`,
    });
  },
};
```

In `wrangler.jsonc`, schedule it for 17:00 UTC and set the app ID:

```json
{
  "name": "daily-summary",
  "main": "src/index.js",
  "compatibility_date": "2026-10-01",
  "triggers": { "crons": ["0 17 * * *"] },
  "vars": { "PUSHGENIUS_APP_ID": "YOUR_APP_ID" }
}
```

Save the key as a secret and deploy:

```sh
npx wrangler secret put PUSHGENIUS_API_KEY
npx wrangler deploy
```

To try it locally, put `PUSHGENIUS_API_KEY=YOUR_REST_API_KEY` in `.dev.vars`, run `npx wrangler dev --test-scheduled`, and open `http://localhost:8787/__scheduled`.

Source: https://pushgeni.us/docs/serverless
