Guides

Push

Firebase Cloud Messaging from ctx.push.send, plus an optional device registry you can test from the dashboard.

Open /projects/:id/push and paste a Firebase service-account JSON (encrypted). Optionally store a web VAPID key. Call ctx.push.send({ token or tokens, title, body, data? }). Native APNs without Firebase is not supported.

  • Create a Firebase project and enable Cloud Messaging.
  • Android: add google-services.json to the mobile app.
  • iOS: upload an APNs key to Firebase, not to Robodev.
  • Web: use firebaseConfig, request permission, send the FCM token to your API.

api/notify.ts

import { defineApi, z } from "@robodev-ai/sdk";

export const post = defineApi({
  body: z.object({ token: z.string(), title: z.string(), body: z.string() }),
  handler: async ({ push, body }) => push.send(body),
});

Device registry

You can keep device tokens in your own tables, or let Robodev keep an optional registry per project. Call ctx.push.registerDevice({ token, platform, userId?, label? }) from your own authenticated API route when the app hands you a token; platform is android, ios, or web. Registering the same token again updates its platform, userId, label, and last-seen time and returns created: false. ctx.push.unregisterDevice({ token }) removes it and returns { removed } (unknown tokens return removed: false). Registering works before Firebase is configured. ctx.push.send still takes tokens; it does not look users up in the registry.

api/push-token.ts

import { defineApi, z } from "@robodev-ai/sdk";

export const post = defineApi({
  auth: "required",
  body: z.object({
    token: z.string().min(1),
    platform: z.enum(["android", "ios", "web"]),
    label: z.string().max(100).optional(),
  }),
  handler: async ({ push, user, body }) =>
    push.registerDevice({ ...body, userId: user!.id }),
});

export const del = defineApi({
  auth: "required",
  body: z.object({ token: z.string().min(1) }),
  handler: async ({ push, body }) => push.unregisterDevice(body),
});
  • Tokens are encrypted at rest and only ever shown as …last6. Labels are up to 100 characters, userId up to 200, tokens up to 4,096.
  • Dead tokens are pruned: when FCM answers UNREGISTERED, or INVALID_ARGUMENT for the token itself, the device is removed from the registry. This applies to ctx.push.send and to dashboard test sends; send still returns or throws exactly as before. Other failures keep the device.
  • Push → Devices lists up to 200 devices (most recently seen first) with search by label, user ID, or token suffix and a platform filter. Add device registers one by hand; Remove deletes one.
  • Send test sends a real notification to one device with an optional shared title and body (defaults: Robodev test notification / Sent from the Robodev dashboard.). Test sends appear in Push → Logs and count toward the 60-per-minute rate limit and the hourly push quota. They need Firebase configured.
  • Clearing the Firebase settings keeps the registry. Deleting the project deletes it.
  • robodev dev: registerDevice and unregisterDevice throw push_not_configured, like send.