Push Notification Payload Reference

Updated: 2026-08-27 08:24 ET · Audited: 2026-06-26

TL;DR: Contract reference for the content-driven push notification payload. Routing is driven by contentTypeDocument, WebLink, DeepLink, FlightNotification, or empty string (title/message rendered in a WebView) — with destination, docType, and fileId conditionally required. Deep links use the PageName?Param=Value format against a fixed set of supported pages. requiresLogin and iconUrl are required: the parser reads both unguarded, so omitting either throws KeyNotFoundException and drops the notification.

This document defines the payload contract used by ALPA Mobile for content-driven push notifications.

Overview

The app supports content payloads that route users to one of these content types:

The docType field further identifies render behavior for document content, such as pdf or htm.

Field definitions

FieldRequiredTypeDescription
idYesstringUnique content identifier as string.
titleYesstringNotification title shown to the user.
messageYesstringNotification body text.
contentTypeYesstringOne of Document, WebLink, DeepLink, FlightNotification, or empty string (displays title/message in WebView).
destinationConditionalstringURL or route target. Required for Document, WebLink, and DeepLink.
docTypeConditionalstringRequired for Document; typical values: pdf, htm, webpage.
fileIdConditionalstringDocument file identifier when source is a managed file.
sourceNostringUpstream content source identifier (e.g. sitecore).
correlationKeyNo — but required in practice on FlightNotificationstringGroups related notifications — used as the Android notification group (FirebaseService.SetGroup). Defaults to a fresh GUID when omitted. On a flight alert it carries the fs-{ScheduleKey} audience the push was addressed to, and that is what a tap routes by (see Flight alert routing below): with it, the tap opens that flight's detail screen; without it, the tap can only reach the alert list.
portalIdNonumberDeprecated — Legacy portal identifier (not parsed by the app).
requiresLoginYesstring"true"/"false" — sets RequiresAuthentication. Read unguarded in PushNotification.PushNotificationFromFBM/FromAPNS; omission throws KeyNotFoundException.
iconUrlYesstringRead unguarded in both parse paths; omission throws KeyNotFoundException. Value may be empty but the key must be present.
iconUrl2NostringOptional secondary icon URL (parsed when present).
iconUrl3NostringOptional tertiary icon URL (parsed when present).

Payload examples

Every payload must also carry the requiresLogin and iconUrl keys (values may be "false"/empty); the examples below predate that finding and omit them.

Document (HTML)

{
  "id": "0",
  "message": "Commemorating the Passage of Historic Pilot Qualification and Training Legislation",
  "title": "FastRead",
  "contentType": "Document",
  "docType": "htm",
  "source": "sitecore",
  "destination": "~/media/F994CC65B5FB45ECABD1BF61F5C85E61.ashx?modified=20230803T2128Z",
  "fileId": "{F994CC65-B5FB-45EC-ABD1-BF61F5C85E61}"
}

Document (PDF)

{
  "id": "1005",
  "message": "ALPA MAG Test",
  "title": "Alpa Mag Test",
  "contentType": "Document",
  "destination": "~/media/D65CA7D4314B43C6B75A1C5181B1D475.ashx?modified=1589232930000",
  "docType": "pdf",
  "fileId": "{D65CA7D4-314B-43C6-B75A-1C5181B1D475}",
  "source": "sitecore"
}

Document (Website)

{
  "id": "1000",
  "message": "Live Article Test",
  "title": "Test Article",
  "contentType": "Document",
  "destination": "https://mag.alpa.org/Articles/mag-hotline-april-9",
  "docType": "webpage"
}
{
  "id": "01",
  "message": "Testing with google link",
  "title": "Weblink Test",
  "contentType": "WebLink",
  "destination": "https://google.com"
}

Flight notification

Flight-change alerts for saved flights. Tapping opens the Flight Finder notifications tab with the tapped alert expanded (PushNotificationHandler); delivered to the fs-{ScheduleKey} audience via Azure Notification Hub.

{
  "id": "188040",
  "message": "DL5328 from JFK to SYR now arrives at 07/29/2026 15:38.",
  "title": "Flight Changed",
  "contentType": "FlightNotification",
  "correlationKey": "fs-9fceb91f-0488-41ac-a2ab-40619d8d155c"
}

Title and message in WebView body

When contentType is empty, the app displays the title and message directly in a WebView:

{
  "id": "01",
  "message": "Testing message goes here",
  "title": "Testing title goes here",
  "contentType": ""
}

The MAUI app uses a simplified deep link format with the page name followed by optional query parameters.

Format: PageName?QueryParam1=Value1&QueryParam2=Value2

Supported pages (the Blazor Hybrid app resolves the same strings via DeepLinkResolver.cs, which maps each page name to a Blazor route — 27 mapped names plus two pseudo-pages):

Page nameBlazor route
HomePage/home
UserProfilePage/profile
SettingsPage/profile (settings live in a section of the profile page)
FavoritesPage/favorites
DocumentCenterPage/documents
DocumentsListPage/documents
DocumentsPage/documents
FlightDutyPeriodListPage/ftdt/dashboard
JumpseatFlightFinderSavedFlightsPage/jumpseat/saved
JumpseatFlightFinderFrequentSearchesPage/jumpseat/recent
PushNotificationsListPage/notifications
PushNotificationsSettingsPage/notifications/settings
MemberResourcesPage/member-resources
MyPilotGroupPage/mec
PilotGroupCommitteePage/mec/committees
PilotGroupEventsPage/mec/events
PilotGroupHotelsPage/mec/hotels
PilotGroupRepresentativesPage/mec/reps
KCMHomePage/kcm
KCMAirlinesPage/kcm/airlines
KCMAirportsPage/kcm/airports
JumpseatInfoPage/jumpseat/search
JumpseatFlightFinderSearchPage/jumpseat/search
JumpseatAirlinePolicyPage/jumpseat/airline-policies
JumpseatEtiquettePage/jumpseat/etiquette
JumpseatMissionPage/jumpseat/mission
AdvocacyPage/advocacy

Pseudo-pages (intercepted, not navigated to):

Query keys are carried across with keys lowercased (native binds Scope, Blazor binds scope). An unmapped page name is reported as unresolved rather than guessed.

WebViewPage?... parameters (native AppShell.OnNavigating only):

Since AB#2591, BannerSubtitle/ImageGlyph/ImageGlyphFontFamily are still parsed but no longer rendered anywhere — AuthenticatedWebViewPage's header has one title slot (falls back BannerTitle → page title), no subtitle or glyph slot.

{
  "id": "1000",
  "message": "DeepLink notification",
  "title": "DeepLink notification",
  "contentType": "DeepLink",
  "destination": "DocumentCenterPage?Scope=ALPA"
}

Validation notes

Flight alert routing (2026-08-14)

A tapped FlightNotification opens the flight the alert is about, not a list of alerts. PushNotificationHandler strips the fs- prefix off correlationKey to recover the schedule key and routes to /jumpseat/flight-detail/alert/{ScheduleKey}?notif={id}; the screen resolves that key against the loaded search results, then against Saved Flights, where a subscribed flight always is (subscribing to alerts saves the flight). Back from there returns to the alert list on the Flight Finder tab with the tapped alert focused. A payload with no correlationKey — or one whose key matches no flight on the device — still lands on /notifications?tab=flight&focus={id}, which is where every flight tap went before.

Hub template note. The field only reaches the device if the registration template carries it. The Android and silent-iOS templates always have; the visible-iOS template did not until 2026-08-14 (Constants.FSNotificationHubRegistrationTemplateiOS), so an iOS tap had nothing to route by regardless of what the sender supplied. Devices pick the added field up on their next hub registration, which happens at app start.