Unified Order Service
Home
Getting Started
  • Core API
  • Drone API
Resources
Home
Getting Started
  • Core API
  • Drone API
Resources
  • Introduction

    • Getting Started
    • System Overview
    • Authentication
  • Core Concepts

    • Working with Orders
    • Working with Channels
    • Places
    • Storage Locations
    • Places Management Dashboard
  • Integration

    • Webhooks
    • Order Status Workflows
    • FCM Push Notifications
  • Advanced Topics

    • API Keys
    • Order Versioning
    • Picking App Integration Guide
    • Subscriptions
    • Cancellation Reasons

FCM Push Notifications

This guide explains the Firebase Cloud Messaging (FCM) push notification system in the Unified Order Service (UOS) API. This system sends real-time notifications to mobile devices when order events occur.

What are FCM Notifications?

FCM notifications in UOS are data-only push notifications sent to mobile devices when specific order events occur. The system uses Firebase Cloud Messaging to deliver:

  • Order status change notifications when orders progress through their lifecycle
  • Timeslot monitoring notifications for delivery window management
  • Reminder notifications for unpicked orders
  • Order creation notifications when new orders are received

How It Works

1. Device Registration

Devices register their FCM tokens using the subscriptions endpoints to receive notifications for specific places.

2. Event Triggers

The system automatically sends notifications when:

  • Orders are created
  • Order status changes (pending → processing → picking → picked, etc.)
  • Timeslots begin (2:00 PM for delivery windows)
  • Reminders are needed (2:15, 2:30, 2:45 PM if orders remain unpicked)

3. Notification Delivery

All notifications use data-only payloads (no title/body) - your mobile app handles the presentation.

Event Types

Order Created (event_order_created)

Triggered when: A new order is created in the system

Payload Example:

{
  "default": {
    "data": {
      "message_id": "msg-1725707721000-abc123def",
      "order_id": "742ba33c-0c02-43e7-80b0-eb795c14dc6f",
      "parent_order_id": "742ba33c-0c02-43e7-80b0-eb795c14dc6f",
      "visible_id": "ORDER-20250707-1021",
      "event_type": "event_order_created",
      "delivery_date": "2025-07-07",
      "start_time": "14:00",
      "end_time": "16:00",
      "place_id": "1ee68c4e-7008-4227-a92d-e1b13ac64f30"
    }
  }
}

Order Status Changed (event_order_status_changed)

Triggered when: Order status changes (pending → processing → picking → picked → retrieving → shipped → completed)

Payload Example:

{
  "default": {
    "data": {
      "message_id": "msg-1725707721000-xyz789ghi",
      "order_id": "742ba33c-0c02-43e7-80b0-eb795c14dc6f",
      "parent_order_id": "742ba33c-0c02-43e7-80b0-eb795c14dc6f",
      "visible_id": "ORDER-20250707-1021",
      "event_type": "event_order_status_changed",
      "delivery_date": "2025-07-07",
      "start_time": "14:00",
      "end_time": "16:00",
      "place_id": "1ee68c4e-7008-4227-a92d-e1b13ac64f30",
      "previous_status": "pending",
      "new_status": "processing",
      "order_number": "ORDER-20250707-1021"
    }
  }
}

Timeslot Started (event_timeslot_started)

Triggered when: Delivery timeslots begin (typically 2:00 PM)

Payload Example:

{
  "default": {
    "data": {
      "message_id": "msg-1725714000000-def456ghi",
      "order_id": "742ba33c-0c02-43e7-80b0-eb795c14dc6f",
      "parent_order_id": "742ba33c-0c02-43e7-80b0-eb795c14dc6f",
      "visible_id": "ORDER-20250707-1021",
      "event_type": "event_timeslot_started",
      "delivery_date": "2025-07-07",
      "start_time": "14:00",
      "end_time": "16:00",
      "place_id": "1ee68c4e-7008-4227-a92d-e1b13ac64f30"
    }
  }
}

Unpicked Orders Reminder (event_unpicked_orders_reminder)

Triggered when: Orders remain unpicked after timeslot reminders (2:15, 2:30, 2:45 PM)

Payload Example:

{
  "default": {
    "data": {
      "message_id": "msg-1725714900000-ghi789jkl",
      "order_id": "742ba33c-0c02-43e7-80b0-eb795c14dc6f",
      "parent_order_id": "742ba33c-0c02-43e7-80b0-eb795c14dc6f",
      "visible_id": "ORDER-20250707-1021",
      "event_type": "event_unpicked_orders_reminder",
      "delivery_date": "2025-07-07",
      "start_time": "14:00",
      "end_time": "16:00",
      "place_id": "1ee68c4e-7008-4227-a92d-e1b13ac64f30"
    }
  }
}

Notification Payload Structure

All FCM notifications use the same standardized payload structure:

Core Fields (Always Present)

FieldTypeDescription
message_idstringUnique message identifier
order_idstringOrder ID (primary identifier)
parent_order_idstringParent order ID (usually same as order_id)
visible_idstringVisible order identifier (order number, reference ID, or ID)
event_typestringEvent type (see Event Types above)
delivery_datestringDelivery date in YYYY-MM-DD format
start_timestringTimeslot start time in HH:MM format
end_timestringTimeslot end time in HH:MM format
place_idstringPlace identifier

Event-Specific Fields

FieldTypePresent WhenDescription
previous_statusstringStatus change eventsPrevious order status
new_statusstringStatus change eventsNew order status
order_numberstringStatus change eventsOrder number

Timeslot Monitoring System

The system includes automated timeslot monitoring that runs every 15 minutes:

Monitoring Schedule

  • 2:00 PM: Timeslot started notification (event_timeslot_started)
  • 2:15 PM: First reminder if orders still unpicked (event_unpicked_orders_reminder)
  • 2:30 PM: Second reminder if orders still unpicked (event_unpicked_orders_reminder)
  • 2:45 PM: Final reminder if orders still unpicked (event_unpicked_orders_reminder)

Monitored Statuses

Orders are considered "unpicked" when in these statuses:

  • pending
  • processing
  • picking

Once orders reach picked, retrieving, shipped, or completed, they no longer trigger reminder notifications.

Fallback Handling

The system includes robust fallback mechanisms for missing data:

Timeslot Extraction

The system attempts to extract timeslot information from multiple sources:

  1. Primary: order.shipping_info.slot.start_time / end_time
  2. Salesforce: order.metadata.delivery_slot_start / delivery_slot_end
  3. Drone API: order.shipping_info.pickup_details.time_slot
  4. Fallback: 00:00-23:59 if no timeslot data available

Date Extraction

The system attempts to extract delivery dates from:

  1. Primary: order.shipping_info.slot.date
  2. Salesforce: order.metadata.delivery_slot_start
  3. Drone API: order.shipping_info.slot.delivery_date
  4. Fallback: order.order_date or current date

Mobile App Integration

Receiving Notifications

// React Native example
import messaging from '@react-native-firebase/messaging';

// Handle background messages
messaging().setBackgroundMessageHandler(async remoteMessage => {
  const { data } = remoteMessage;
  
  switch (data.event_type) {
    case 'event_order_created':
      handleOrderCreated(data);
      break;
    case 'event_order_status_changed':
      handleStatusChange(data);
      break;
    case 'event_timeslot_started':
      handleTimeslotStarted(data);
      break;
    case 'event_unpicked_orders_reminder':
      handleUnpickedReminder(data);
      break;
  }
});

// Handle foreground messages
messaging().onMessage(async remoteMessage => {
  const { data } = remoteMessage;
  showInAppNotification(data);
});

Processing Notification Data

function handleOrderCreated(data) {
  const {
    message_id,
    order_id,
    delivery_date,
    start_time,
    end_time,
    place_id
  } = data;
  
  // Show notification
  showNotification(
    'New Order Received',
    `Order for ${delivery_date} ${start_time}-${end_time}`,
    { orderId: order_id, placeId: place_id }
  );
  
  // Update app state
  refreshOrders();
}

function handleStatusChange(data) {
  const {
    order_id,
    order_number,
    previous_status,
    new_status
  } = data;
  
  // Show status change notification
  showNotification(
    'Order Status Updated',
    `Order #${order_number} is now ${new_status}`,
    { orderId: order_id }
  );
  
  // Update specific order in app
  updateOrderStatus(order_id, new_status);
}

function handleTimeslotStarted(data) {
  const {
    delivery_date,
    start_time,
    end_time,
    place_id
  } = data;
  
  // Show timeslot notification
  showNotification(
    'Delivery Window Started',
    `${delivery_date} ${start_time}-${end_time}`,
    { placeId: place_id }
  );
  
  // Navigate to order management
  navigateToOrders();
}

Testing Notifications

Test Order Creation

# Create order to trigger notifications
curl -X POST "https://api.uos.example.com/v1/orders" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel_id": "7eb292fd-aa7c-4357-ba05-debb11998192",
    "place_id": "1ee68c4e-7008-4227-a92d-e1b13ac64f30",
    "order_number": "TEST-ORDER-001",
    "shipping_info": {
      "slot": {
        "start_time": "14:00",
        "end_time": "16:00",
        "date": "2025-07-07"
      }
    }
  }'

Test Status Changes

# Update order status to trigger status change notifications
curl -X PATCH "https://api.uos.example.com/v1/orders/ORDER_ID/status" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "processing"
  }'

Monitoring and Debugging

Checking Notification Logs

The system logs all notification activities:

# Check notification logs
grep "Event notification sent" /var/log/uos/app.log
grep "FCM notification" /var/log/uos/app.log

Verifying Device Registration

# Check if devices are registered for a place
curl -X GET "https://api.uos.example.com/debug/places/PLACE_ID/subscriptions" \
  -H "Authorization: Bearer YOUR_API_KEY"

Best Practices

App Development

  • Handle all event types: Implement handlers for all notification types
  • Validate data: Always validate notification payloads before processing
  • Provide feedback: Show users what actions triggered notifications
  • Cache intelligently: Cache order data locally to complement notifications

Notification Management

  • Register early: Register FCM tokens as soon as permissions are granted
  • Update regularly: Refresh tokens when they change
  • Clean up: Remove tokens when users log out or uninstall

Error Handling

  • Graceful degradation: App should work even if notifications fail
  • Retry logic: Implement retry mechanisms for failed registrations
  • Logging: Log notification events for debugging

Troubleshooting

Common Issues

No notifications received:

  1. Check device token registration
  2. Verify place ID is correct
  3. Confirm Firebase configuration
  4. Check notification permissions

Duplicate notifications:

  1. Verify single device registration per place
  2. Check for multiple app instances
  3. Confirm proper token cleanup

Missing timeslot data:

  1. System uses fallback values (00:00-23:59)
  2. Check order creation payload includes shipping_info
  3. Verify timeslot format matches expected structure

Delayed notifications:

  1. FCM delivery can be delayed by device/network conditions
  2. Check device battery optimization settings
  3. Verify app is not being killed by OS

The FCM notification system provides reliable, real-time updates to mobile applications with comprehensive fallback handling and robust error management.

Last Updated: 12/1/25, 11:31 AM
Prev
Order Status Workflows