Appearance
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
| Provider | Platforms | Token format | Credentials needed |
|---|---|---|---|
| Expo Push | iOS + Android (Expo apps) | ExponentPushToken[...] | Access token (optional) |
| FCM (Firebase) | Android + iOS + Web | Long alphanumeric (~150+ chars) | Service account JSON |
| APNS (Apple) | iOS only | 64 hex characters | Team 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
- Go to Channels → Push Notifications in your dashboard
- 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
- 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:
| Field | Maps to | Required |
|---|---|---|
| Title | Notification title (bold text) | Yes |
| Body | Notification body text | Yes |
Templates support Handlebars variables:
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
- Check the contact has push tokens: Contacts → [contact] → Push Tokens
- Verify push integration is installed: Channels → Push Notifications
- Ensure the event has push channel enabled: Events → [event]
- 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
- Routing — Force push vs auto-routing
- Deliveries — Statuses and failure reasons
- Templates — Dynamic content
- Contacts — Managing contact identifiers