Skip to content

Push Notifications

Send push notifications to iOS, Android, and Expo apps. Sendivent supports multiple push providers and automatically routes each device token to the correct one.

INFO

Your push integration is shared between sandbox and production — set it up once, use it everywhere.

Supported providers

ProviderPlatformsToken formatCredentials needed
Expo PushiOS + Android (Expo apps)ExponentPushToken[...]Access token (optional)
FCM (Firebase)Android + iOS + WebLong alphanumeric (~150+ chars)Service account JSON
APNS (Apple)iOS only64 hex charactersTeam ID, Key ID, p8 key, Bundle ID

Sendivent auto-detects which provider to use based on the token format — you don't need to specify the provider when sending.

Setup

  1. Go to Channels → Push Notifications in your dashboard
  2. Add credentials for the providers you use:
    • Expo apps: Leave empty (works without a token) or add an access token for higher rate limits
    • Firebase apps: Paste your service account JSON from the Firebase Console
    • Native iOS apps: Add your APNS Team ID, Key ID, p8 key file contents, and Bundle ID
  3. Click Save — the integration is verified automatically

You can configure one, two, or all three providers. Sendivent routes each token to the right one.

Device registration

Push tokens must be registered on a contact before you can send notifications. Call the registration endpoint from your mobile app on startup:

typescript
const sendivent = new Sendivent('YOUR_API_KEY');

// Register device token on a contact
await sendivent.contacts.registerPushToken('user-123', expoPushToken);

// Or upsert the contact with the token in one call
await sendivent.contacts.upsert({
  id: 'user-123',
  name: 'Alice',
  email: 'alice@example.com',
  push_token: expoPushToken
});
php
$sendivent = new Sendivent('YOUR_API_KEY');

// Register device token
$sendivent->contacts()->registerPushToken('user-123', $expoPushToken);

// Or upsert
$sendivent->contacts()->upsert([
  'id' => 'user-123',
  'name' => 'Alice',
  'push_token' => $expoPushToken
]);
bash
curl -X POST https://api.sendivent.com/v1/contacts/user-123/push-tokens \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"token": "ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]"}'

How registration works

  • Additive — registering a new token doesn't remove existing ones (multi-device support)
  • Idempotent — registering the same token twice is safe (no duplicates created)
  • Restores suppressed tokens — if a token was previously invalidated, re-registering it restores it

Removing tokens

Remove a token when the user logs out:

typescript
await sendivent.contacts.removePushToken('user-123', expoPushToken);

Automatic invalidation

When a provider reports a token as invalid (e.g., Expo's DeviceNotRegistered, FCM's UNREGISTERED, APNS 410 Gone), Sendivent automatically suppresses the token. It won't be used for future sends until re-registered.

Sending push notifications

Once a contact has registered push tokens, send notifications like any other channel:

typescript
await sendivent
  .event('order-shipped')
  .to({ id: 'user-123' })
  .payload({ tracking_url: 'https://...' })
  .send();
bash
curl -X POST https://api.sendivent.com/v1/send/order-shipped \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": {"id": "user-123"},
    "payload": {"tracking_url": "https://..."}
  }'

If the contact has push tokens and the event has push enabled, the notification is delivered to all registered devices.

Force push channel

To send only via push (skip email/SMS/Slack):

typescript
await sendivent
  .event('order-shipped')
  .channel('push')
  .to({ id: 'user-123' })
  .send();

Templates

Push notification templates have two fields:

FieldMaps toRequired
TitleNotification title (bold text)Yes
BodyNotification body textYes

Templates support Handlebars variables:

handlebars
Title: Order shipped!
Body: Hey {{contact.name}}, your order is on its way. {{payload.tracking_url}}

Configure templates in Events → [your event] → Push in the dashboard.

Getting push tokens in your app

Expo

typescript
import * as Notifications from 'expo-notifications';
import * as Device from 'expo-device';

async function registerForPush() {
  if (!Device.isDevice) return null;

  const { status } = await Notifications.requestPermissionsAsync();
  if (status !== 'granted') return null;

  const { data: token } = await Notifications.getExpoPushTokenAsync({
    projectId: 'your-expo-project-id',
  });

  // Register with Sendivent
  await sendivent.contacts.registerPushToken(userId, token);
  return token;
}

React Native (FCM)

typescript
import messaging from '@react-native-firebase/messaging';

const token = await messaging().getToken();
await sendivent.contacts.registerPushToken(userId, token);

// Listen for token refresh
messaging().onTokenRefresh(async (newToken) => {
  await sendivent.contacts.registerPushToken(userId, newToken);
});

Native iOS (APNS)

Use the device token from didRegisterForRemoteNotificationsWithDeviceToken (64 hex chars).

Troubleshooting

Push notification not delivered

  1. Check the contact has push tokens: Contacts → [contact] → Push Tokens
  2. Verify push integration is installed: Channels → Push Notifications
  3. Ensure the event has push channel enabled: Events → [event]
  4. Check Activity log for delivery status and error details

Token rejected / DeviceNotRegistered

The push token is no longer valid. Common causes:

  • App was uninstalled
  • App was reinstalled (new token generated)
  • Token expired

The token is automatically suppressed. The app will register a new token on next launch.

Wrong provider used

Sendivent auto-detects the provider from the token format. If routing seems wrong, verify the token format matches the expected pattern (see Supported providers table above).

See also

Released under the MIT License.