Customer Notifications
Levy Fleets uses push notifications to keep customers informed about their rides, account status, promotions, and important updates. This guide covers notification types, how to send manual notifications, automatic system notifications, and troubleshooting delivery issues.
Overview
The notification system uses Expo Push Notifications to deliver messages to customer mobile devices. Notifications are sent for:
- Ride-related events (start, end, issues)
- Zone alerts (entering/leaving zones)
- Payment notifications (successful charges, failed payments)
- Wallet updates (credits added)
- Promotional messages (promos, announcements)
- System alerts (maintenance, updates)
- Identity verification (required, cleared)
Notification Types
System-Generated Notifications
These are automatically triggered by events in the system:
| Type | Trigger | Example Message |
|---|---|---|
ride | Ride events | "Your ride has ended. Total: $5.00" |
zone | Zone boundary crossed | "You're leaving the service area" |
payment | Payment processed | "Payment of $10.00 successful" |
wallet | Balance changed | "You received $5.00 credit" |
identity | Verification status | "Identity verification required" |
system | Platform alerts | "Scheduled maintenance tonight" |
Manual Notifications
Operators can send custom notifications to individual customers or groups:
| Use Case | When to Use |
|---|---|
| Service updates | Inform about local changes |
| Promotional offers | Announce discounts or events |
| Account issues | Request action from customer |
| Personal outreach | Customer service follow-up |
Sending Manual Notifications
To Individual Customer
- Navigate to Dashboard > Customers
- Click on the customer to open their detail page
- Click Actions (three-dot menu)
- Select Send Notification
- Fill in the notification form:
- Title: Notification heading (shown bold)
- Body: Main message text
- Type: Category for the notification
- Click Send
Notification Form Fields
| Field | Required | Description |
|---|---|---|
| Title | Yes | Short heading, 50 characters max |
| Body | Yes | Message content, 200 characters max |
| Type | No | Notification category (affects icon/handling) |
| Data | No | Custom JSON data for deep linking |
Type Options
| Type | Icon | Use For |
|---|---|---|
promo | Gift | Promotional offers, discounts |
system | Bell | General announcements |
ride | Scooter | Ride-related messages |
wallet | Wallet | Payment/credit updates |
payment | Card | Payment method issues |
identity | Shield | Verification messages |
API Reference
Send Notification Endpoint
Endpoint: POST /api/customers/notify
Request Body:
{
"customerId": "customer-uuid-here",
"title": "Special Offer!",
"body": "Get 20% off your next ride with code SAVE20",
"type": "promo"
}
Response (Success):
{
"success": true,
"ticketId": "XXXX-XXXX-XXXX-XXXX"
}
Response (Failure):
{
"success": false,
"error": "Customer has no push token"
}
Required Parameters
| Parameter | Type | Description |
|---|---|---|
customerId | string | Customer UUID |
title | string | Notification title |
body | string | Notification body text |
Optional Parameters
| Parameter | Type | Description |
|---|---|---|
type | string | Notification type (see types above) |
data | object | Custom data for deep linking |
sound | string | Sound to play (default/custom) |
badge | number | App badge count |
Deep Linking
Notifications can include data that opens specific screens in the app:
Ride Detail
{
"customerId": "xxx",
"title": "Ride Complete",
"body": "View your ride summary",
"data": {
"screen": "ride",
"rideId": "ride-uuid"
}
}
Wallet
{
"customerId": "xxx",
"title": "Credit Added",
"body": "Check your new balance",
"data": {
"screen": "wallet"
}
}
Identity Verification
{
"customerId": "xxx",
"title": "Verify Your Identity",
"body": "Complete verification to continue riding",
"data": {
"screen": "identity_verification"
}
}
Automatic Notifications
Ride Notifications
| Event | Title | Body Example |
|---|---|---|
| Ride Started | "Ride Started" | "Enjoy your ride on [Vehicle ID]" |
| Ride Ended | "Ride Complete" | "Your ride: $5.00 for 15 minutes" |
| Ride Paused | "Ride Paused" | "Your ride is paused" |
| Low Battery Warning | "Low Battery" | "Vehicle battery is low, end ride soon" |
| Out of Zone | "Leaving Service Area" | "You're about to leave the service zone" |
| Auto-End Warning | "Ride Ending Soon" | "Your ride will auto-end in 5 minutes" |
Payment Notifications
| Event | Title | Body Example |
|---|---|---|
| Charge Successful | "Payment Successful" | "Payment of $10.00 processed" |
| Charge Failed | "Payment Failed" | "We couldn't process your payment" |
| Card Expiring | "Card Expiring" | "Your card expires next month" |
| Subscription Renewed | "Subscription Renewed" | "Your monthly plan has renewed" |
Wallet Notifications
| Event | Title | Body Example |
|---|---|---|
| Credit Added | "Credit Added" | "You received $5.00 credit" |
| Bonus Applied | "Bonus Credit" | "$3.00 bonus added to your account" |
| Low Balance | "Low Balance" | "Add funds to continue riding" |
| Refund Issued | "Refund Processed" | "$2.50 has been refunded" |
| Negative Balance | "Wallet balance negative" | "A charge of $25.00 was applied..." |
| Auto Top-up | "Wallet Topped Up" | "$15.00 was added to your wallet" |
Negative Balance Notification
Automatic Alert
When an operator uses "Charge Fee" and the customer's balance crosses from positive to negative, an automatic notification is sent to ensure customers are aware of the debt.
Trigger Conditions:
- Wallet balance was $0 or positive before the charge
- Balance becomes negative after the charge
- Only triggered by "Charge Fee" action, not "Reduce Balance"
Notification Content:
- Title: "Wallet balance negative"
- Body: "A charge of $X.XX was applied to your account. Your wallet balance is now -$Y.YY."
- Type:
wallet
Identity Notifications
| Event | Title | Body Example |
|---|---|---|
| Verification Required | "Verify Your Identity" | "Complete verification to ride" |
| Verification Cleared | "Good to Go!" | "Your account is verified" |
| Verification Failed | "Verification Issue" | "Please try verification again" |
Notification Settings
Customer Preferences
Customers can control notifications in the mobile app:
- All Notifications: Master toggle
- Ride Updates: Start, end, alerts
- Promotions: Marketing messages
- Payment Alerts: Transaction confirmations
Subaccount Configuration
Operators can configure notification behavior:
| Setting | Description |
|---|---|
notifications_enabled | Master toggle for subaccount |
promo_notifications | Allow promotional messages |
marketing_frequency | Limit marketing notifications |
Push Token Management
How Tokens Work
- Customer installs app and grants notification permission
- App receives push token from Expo/APNs/FCM
- Token is stored on customer record (
expo_push_token) - Notifications sent to this token
- Token may change (reinstall, device change)
Token Status
| Status | Meaning | Action |
|---|---|---|
| Valid token | Customer can receive notifications | None needed |
| No token | App not installed or permissions denied | Cannot send |
| Invalid token | Token expired or revoked | Token will be refreshed |
When Tokens Become Invalid
- Customer uninstalls the app
- Customer revokes notification permission
- Device is reset or replaced
- Token expires (rare)
Delivery Status
Expo Push Receipts
When a notification is sent, Expo provides:
- Ticket ID: Immediate confirmation of submission
- Receipt: Eventual delivery status
Receipt Status Values
| Status | Meaning |
|---|---|
ok | Delivered successfully |
error | Delivery failed |
DeviceNotRegistered | Token no longer valid |
MessageTooBig | Payload exceeded limit |
MessageRateExceeded | Too many messages sent |
Error Handling
Common errors and resolutions:
| Error | Cause | Resolution |
|---|---|---|
DeviceNotRegistered | App uninstalled | Remove token from customer |
InvalidCredentials | Expo config issue | Check push credentials |
MessageTooBig | Payload > 4KB | Shorten message |
TooManyRequests | Rate limited | Reduce frequency |
Best Practices
Message Content
- Keep titles short: 30-50 characters maximum
- Be specific: Tell customer what happened or what to do
- Include value: Why should they care?
- Use personalization: Include name or relevant details
- Call to action: What should they do next?
Frequency
- Don't over-notify: Limit promotional messages
- Batch when possible: Combine related updates
- Respect time zones: Send during waking hours
- Emergency only: Reserve for truly important alerts
Timing
| Notification Type | Best Time | Avoid |
|---|---|---|
| Promotional | 10am-8pm local | Before 9am, after 9pm |
| Transactional | Immediately | N/A |
| Ride alerts | Immediately | N/A |
| Weekly digest | Weekend morning | Monday |
Tone
- Friendly: "Your ride is complete!"
- Clear: "Payment of $5.00 processed"
- Actionable: "Verify your identity to continue riding"
- Avoid: ALL CAPS, excessive punctuation, emoji overload
Bulk Notifications
Current Limitations
The dashboard currently supports individual notifications only. For bulk notifications:
- Use the API with a loop
- Implement rate limiting (max 400/minute to Expo)
- Consider a separate notification campaign tool
API Bulk Pattern
// Example: Send to multiple customers
const customerIds = ['cust1', 'cust2', 'cust3'];
const message = {
title: 'Special Offer',
body: 'Get 20% off this weekend!'
};
for (const customerId of customerIds) {
await fetch('/api/customers/notify', {
method: 'POST',
body: JSON.stringify({ customerId, ...message })
});
// Rate limit: wait 150ms between sends
await new Promise(r => setTimeout(r, 150));
}
Troubleshooting
Notification not received
Check these in order:
-
Customer has push token?
- View customer detail page
- Check
expo_push_tokenfield - If empty, customer hasn't granted permission
-
Permission enabled?
- Customer must grant notification permission in iOS/Android settings
- They may have disabled it after initial grant
-
App installed?
- Token becomes invalid if app is uninstalled
- Customer needs to reinstall and re-grant permission
-
Correct customer?
- Verify the customerId matches intended recipient
- Check for duplicate accounts
-
Message delivered?
- Check Expo push receipt status
- Look for delivery errors in logs
-
Device issues?
- Do Not Disturb mode on device
- Focus mode blocking notifications
- Low power mode limiting background activity
Customer says they get "too many" notifications
- Review automatic notification triggers
- Check for duplicate sends in logs
- Verify notification preferences are respected
- Consider throttling configuration
Notification shows but with wrong content
- Check for encoding issues in title/body
- Verify data isn't truncated
- Look for special characters being escaped
- Test with plain ASCII text
Notifications delayed
- Expo uses batching, may delay up to few seconds
- APNs/FCM can delay based on device/network
- Check if device is in power save mode
- Verify network connectivity on device
"DeviceNotRegistered" errors
This is normal when:
- Customer uninstalled the app
- Customer got a new device
- Token expired (rare)
Resolution: Remove invalid token from customer record. Token will be refreshed when customer opens app again.
Integration with Other Systems
Ride System
The ride engine sends notifications for:
- Ride start confirmation
- Pause/resume events
- Battery/zone warnings
- Ride completion with summary
- Auto-end notifications
Payment System
Payment processing triggers:
- Successful charge confirmation
- Failed payment alerts
- Refund notifications
- Card expiration warnings
Identity System
Identity verification triggers:
- Verification required prompt
- Verification success confirmation
- Requirement cleared notification
- Failed attempt notification