Abrova
☰ Docs menu · Node.js
Coming soon. Abrova Push is coming soon. This page describes how it will work; it can’t be used yet.

Node.js SDK

Server-side Node.js SDK for sending push notifications, managing devices, templates, segments, scheduled messages, webhooks, and A/B tests.

Node.js 0.1.4Node.js 16+Last updated: 27 Oct 2026
Send to User / Device / Topic

Push to a single device, all of a user's devices, or topic / segment audiences

Broadcast

Single call to push to every registered device

Rich Notifications

Images, action buttons, deep links, custom data

Templates

Reusable notification copy with variable substitution

Segments

Server-evaluated audiences from user metadata

Scheduled Messages

Send at a specific time + timezone

Webhooks

Subscribe to message sent / delivered / failed and device events

Inbox + Receipts + Analytics

Inbox sends, per-device delivery receipts and delivery analytics from the server

Installation#

The SDK installs from Abrova Center in two steps.

  1. Point the @abrova scope at Abrova Center in your project's .npmrc:
# .npmrc (in your project root)
@abrova:registry=https://center.abrova.ir/api/packages/abrova/npm/
  1. Install the package:
bash
npm install @abrova/push-node

Quick Start#

typescript
import { AbrovaPush } from '@abrova/push-node';

const abrovaPush = new AbrovaPush({
  apiKey: process.env.ABROVA_API_KEY,             // ab_live_...
  serverSecret: process.env.ABROVA_SERVER_SECRET, // ab_srv_..., server only
});

await abrovaPush.push.sendToUser({
  userId: 'user-123',
  title: 'Order Shipped',
  body: 'Your order #1234 has been shipped!',
  data: { orderId: '1234' },
});
Server Credentials Required.

Both apiKey and serverSecret are required for all server-side operations. Find them in your Abrova Console under project settings. Never ship the serverSecret to client-side code.

Send Push Notifications#

typescript
// Send to a specific device
await abrovaPush.push.sendToDevice({
  deviceId: 'device-uuid',
  title: 'Hello',
  body: 'Welcome to our app!',
});

// Send to all of a user's devices
await abrovaPush.push.sendToUser({
  userId: 'user-123',
  title: 'New Message',
  body: 'You have a new message',
});

// Send to multiple specific devices
await abrovaPush.push.sendToDevices({
  deviceIds: ['device-1', 'device-2', 'device-3'],
  title: 'Update Available',
  body: 'A new version is available',
});

// Send to a topic
await abrovaPush.push.sendToTopic({
  topic: 'promotions',
  title: 'Flash Sale!',
  body: '50% off everything today only',
  imageUrl: 'https://example.com/sale.jpg',
});

// Send to a segment
await abrovaPush.push.sendToSegment({
  segmentId: 'segment-uuid',
  title: 'Exclusive Offer',
  body: 'Just for our VIP customers',
});

// Broadcast to every registered device
await abrovaPush.push.broadcast({
  title: 'App Update',
  body: 'Check out the new features!',
});

Multi-App Targeting#

If your project hosts multiple apps (e.g. a shopping app and a chat app), use appIdentifier (the bundle ID / package name) to target a specific app:

typescript
await abrovaPush.push.sendToUser({
  userId: 'user-123',
  title: 'New Order',
  body: 'Your order is ready',
  appIdentifier: 'com.myshop.app', // only this app receives it
});
Optional.

appIdentifier is optional. When omitted, the notification is sent to all apps registered under the project. Single-app projects don't need to set it.

Rich Notifications#

typescript
await abrovaPush.push.sendToUser({
  userId: 'user-123',
  title: 'New Product',
  body: 'Check out our latest arrival',
  imageUrl: 'https://example.com/product.jpg',
  actions: [
    { id: 'buy', title: 'Buy Now', action: 'OPEN_PRODUCT' },
    { id: 'later', title: 'Save for Later' },
  ],
  deepLink: 'myapp://product/123',
  data: { productId: '123' },
});

Templates#

Reusable copy with variable substitution. Useful when the same message shape ships in many flows (order shipped, password reset, etc.).

typescript
// Send using a template
await abrovaPush.push.sendToUser({
  userId: 'user-123',
  templateId: 'order-shipped-template',
  templateVariables: {
    orderNumber: '#1234',
    trackingUrl: 'https://track.example.com/1234',
  },
});

// Create a template
const template = await abrovaPush.templates.create({
  name: 'Order Shipped',
  title: 'Your order {{orderNumber}} has shipped!',
  body: 'Track your package: {{trackingUrl}}',
  variables: ['orderNumber', 'trackingUrl'],
});

// List templates
const templates = await abrovaPush.templates.list();

// Preview render
const rendered = await abrovaPush.templates.render(template.id, {
  orderNumber: '#1234',
  trackingUrl: 'https://track.example.com/1234',
});

Inbox Messages#

Push delivers a message to the device. Inbox stores it persistently so the user can revisit later.

typescript
// Send inbox message to a user
await abrovaPush.inbox.sendToUser({
  userId: 'user-123',
  content: {
    title: 'Welcome!',
    body: 'Thanks for joining us.',
    imageUrl: 'https://example.com/welcome.jpg',
    deepLink: 'myapp://onboarding',
  },
});

// Send to multiple users
await abrovaPush.inbox.sendToUsers({
  userIds: ['user-1', 'user-2', 'user-3'],
  content: { title: 'New Feature', body: 'Check out our latest feature' },
});

// Broadcast with expiry
await abrovaPush.inbox.broadcast({
  content: { title: 'Holiday Sale', body: 'Up to 70% off!' },
  expiresAt: '2025-12-31T23:59:59Z',
});

Device Management#

typescript
// List all devices
const devices = await abrovaPush.devices.list();

// Subscribe a device to a topic
await abrovaPush.devices.subscribeTopic('device-uuid', 'news');
await abrovaPush.devices.unsubscribeTopic('device-uuid', 'news');

// Associate device with a user
await abrovaPush.devices.setUserId('device-uuid', 'user-123');

// Delete a device
await abrovaPush.devices.delete('device-uuid');

// Paginated, filtered list (includes inactive devices unless isActive is set)
const { items, total } = await abrovaPush.devices.listPage({
  platform: 'ios',
  isActive: true,
  page: 1,
  limit: 50,
});

// Values you can filter on (app versions, SDK versions, failure reasons)
const options = await abrovaPush.devices.filterOptions();

// Stop sending to a device but keep its history, and undo it
await abrovaPush.devices.unregister('device-uuid');
await abrovaPush.devices.reactivate('device-uuid');

Segments#

Segments evaluate user metadata server-side. Use them when you need "all users with more than 10 orders" or "all users in Tehran on the premium tier."

typescript
// Create a segment
const segment = await abrovaPush.segments.create({
  name: 'VIP Customers',
  description: 'Customers with more than 10 orders',
  filters: [
    { field: 'metadata.orders', operator: 'greater_than', value: 10 },
  ],
});

// Get devices in a segment
const devices = await abrovaPush.segments.getDevices(segment.id);

// Recalculate segment membership (e.g. after metadata changes)
await abrovaPush.segments.recalculate(segment.id);

Scheduled Messages#

typescript
// Schedule a message
const scheduled = await abrovaPush.scheduled.create({
  title: 'Reminder',
  body: 'Don\'t forget to complete your purchase!',
  targetType: 'user',
  targetValue: 'user-123',
  scheduledAt: '2025-02-14T09:00:00Z',
  timezone: 'Asia/Tehran',
});

// List pending messages
const pending = await abrovaPush.scheduled.listPending();

// Cancel a scheduled message
await abrovaPush.scheduled.cancel(scheduled.id);

Webhooks#

Subscribe to message (message.sent, message.delivered, message.failed, message.no_recipients) and device (device.registered, device.unregistered, device.updated) events so your backend can react in real time.

typescript
// Create a webhook
const webhook = await abrovaPush.webhooks.create({
  name: 'Order Events',
  url: 'https://example.com/webhooks/abrova-push',
  events: ['message.sent', 'message.delivered', 'message.failed'],
  secret: 'my-secret-key',
});

// Test a webhook
await abrovaPush.webhooks.test(webhook.id, 'message.delivered');

// Read delivery logs for debugging
const logs = await abrovaPush.webhooks.getLogs(webhook.id);

Analytics#

typescript
// Device and message totals, delivery rate, platform distribution
const overview = await abrovaPush.analytics.getOverview();

// Daily breakdown
const daily = await abrovaPush.analytics.getDaily(30); // last 30 days

// App-level totals (devices per platform, topics, users)
const stats = await abrovaPush.analytics.getStats();

Delivery receipts

A send's success count means the push service accepted the notification. Receipts show what happened on each device. See Delivery Receipts.

typescript
const { messageId } = await abrovaPush.push.sendToUser({ userId: 'user-123', title: 'Hi', body: 'Hello' });

// Per device, for one message
const receipts = await abrovaPush.receipts.getForMessage(messageId!);
const stats = await abrovaPush.receipts.getMessageStats(messageId!);

// Receipt log with filters
const { items, total } = await abrovaPush.receipts.list({
  status: 'failed',
  platform: 'android',
  startDate: new Date(Date.now() - 7 * 86400_000),
  page: 1,
  limit: 100,
});

// Delivery analytics (default: last 30 days)
const analytics = await abrovaPush.receipts.analytics({ bucket: 'day' });
console.log(analytics.totals, analytics.byPlatform, analytics.topFailureReasons);

A/B Tests and In-App Messages#

Create A/B tests and in-app messages in Abrova Console.

Error Handling#

typescript
import { AbrovaPush, AbrovaPushError } from '@abrova/push-node';

try {
  await abrovaPush.push.sendToUser({
    userId: 'user-123',
    title: 'Hello',
    body: 'World',
  });
} catch (error) {
  if (error instanceof AbrovaPushError) {
    // error.statusCode, error.message, error.response
  }
}

Configuration#

typescript
const abrovaPush = new AbrovaPush({
  apiKey: process.env.ABROVA_API_KEY!,
  serverSecret: process.env.ABROVA_SERVER_SECRET!,
});

Environment Variables

We recommend storing credentials in environment variables, never in version control:

bash
# .env
ABROVA_API_KEY=ab_live_your_api_key
ABROVA_SERVER_SECRET=ab_srv_your_server_secret

Credential Reference

OptionTypeRequiredDescription
apiKeyStringYesUsed for client-side SDKs and server-side SDKs (ab_live_... format)
serverSecretStringYesRequired for server-side operations (ab_srv_... format). Never expose in client code.

API Reference#

push — sending notifications

OptionTypeRequiredDescription
sendToUser(payload)--Send to all of a user's devices
sendToDevice(payload)--Send to a single device
sendToDevices(payload)--Send to multiple specific devices
sendToTopic(payload)--Send to every subscriber of a topic
sendToSegment(payload)--Send to a segment
broadcast(payload)--Send to every registered device

inbox — persistent message center

OptionTypeRequiredDescription
sendToUser(payload)--Add an inbox message for a single user
sendToUsers(payload)--Add an inbox message for multiple users
broadcast(payload)--Add an inbox message for every user that has a device with a user ID

devices — device management

OptionTypeRequiredDescription
list()--List all active devices
listPage(filters)--Paginated, filtered device list (platform, active, user, app or SDK version, last seen)
filterOptions()--App versions, SDK versions and failure reasons you can filter on
unregister(deviceId)--Stop sending to a device, keep its history
reactivate(deviceId)--Undo unregister
subscribeTopic(deviceId, topic)--Subscribe a device to a topic
unsubscribeTopic(deviceId, topic)--Unsubscribe a device from a topic
setUserId(deviceId, userId)--Associate a device with a user
delete(deviceId)--Delete a device

receipts — per-device delivery

OptionTypeRequiredDescription
getForMessage(messageId)--Receipts for every device a message went to
getMessageStats(messageId)--Sent / delivered / failed counts for one message
getActionStats(messageId)--Clicks per action button
getForDevice(deviceId, limit?)--Recent receipts for one device
list(filters)--Paginated receipt log (platform, status, error, user, device, message, dates)
analytics(options)--Totals, per-platform and per-SDK breakdowns, timeseries, top failure reasons

templates — reusable copy

OptionTypeRequiredDescription
create(payload)--Create a template
list()--List templates
render(id, variables)--Render a template with variable substitution

segments — audience targeting

OptionTypeRequiredDescription
create(payload)--Create a segment with metadata filters
getDevices(segmentId)--Get devices in a segment
recalculate(segmentId)--Recalculate segment membership

scheduled — time-based delivery

OptionTypeRequiredDescription
create(payload)--Schedule a message for a specific time + timezone
listPending()--List pending scheduled messages
cancel(id)--Cancel a scheduled message

webhooks — delivery event subscriptions

OptionTypeRequiredDescription
create(payload)--Create a webhook for message and device events
test(id, eventType)--Trigger a test event
getLogs(id)--Read webhook delivery logs

analytics — delivery + engagement metrics

OptionTypeRequiredDescription
getOverview()--Device and message totals, delivery rate, platform distribution
getDaily(days)--Per-day stats for the last N days
getStats()--App-level totals (devices per platform, topics, users)

Best Practices#

Use Environment Variables

Never hardcode apiKey or serverSecret — load from env so credentials don't end up in version control

Use Templates for Repeated Copy

When the same message shape ships in many flows (order shipped, password reset), templates keep copy consistent and edit-able without a deploy

Topics for Broadcasts, Segments for Targeted

Topics suit large audiences but the user opts in client-side. Segments evaluate server-side metadata — better for "all premium users in Tehran"-style targeting.

Catch AbrovaPushError

Wrap calls in try/catch and check for AbrovaPushError so you can surface statusCode + response to your logs

Subscribe to Webhooks for Real-time Reactions

message.delivered / message.failed / message.no_recipients let your backend react in real time (e.g. mark order as notified, retry on miss)

Was this page helpful?
Report a problem