diff --git a/lib/types/tunnelbroker/notif-types.js b/lib/types/tunnelbroker/notif-types.js
--- a/lib/types/tunnelbroker/notif-types.js
+++ b/lib/types/tunnelbroker/notif-types.js
@@ -7,3 +7,11 @@
   +deviceID: string,
   +payload: string,
 };
+
+export type TunnelbrokerFCMNotif = {
+  +type: 'FCMNotif',
+  +clientMessageID: string,
+  +deviceID: string,
+  +data: string,
+  +priority: 'NORMAL' | 'HIGH',
+};
diff --git a/shared/tunnelbroker_messages/src/messages/mod.rs b/shared/tunnelbroker_messages/src/messages/mod.rs
--- a/shared/tunnelbroker_messages/src/messages/mod.rs
+++ b/shared/tunnelbroker_messages/src/messages/mod.rs
@@ -45,6 +45,7 @@
   // This is due to serde's pattern matching behavior where it prioritizes
   // the first matching pattern it encounters.
   APNsNotif(APNsNotif),
+  FCMNotif(FCMNotif),
   MessageToDeviceRequestStatus(MessageToDeviceRequestStatus),
   MessageToDeviceRequest(MessageToDeviceRequest),
   MessageToDevice(MessageToDevice),
diff --git a/shared/tunnelbroker_messages/src/messages/notif.rs b/shared/tunnelbroker_messages/src/messages/notif.rs
--- a/shared/tunnelbroker_messages/src/messages/notif.rs
+++ b/shared/tunnelbroker_messages/src/messages/notif.rs
@@ -1,7 +1,6 @@
-//! APNs notif built on client.
-
 use serde::{Deserialize, Serialize};
 
+/// APNs notif built on client.
 #[derive(Serialize, Deserialize, PartialEq, Debug)]
 #[serde(tag = "type", rename_all = "camelCase")]
 pub struct APNsNotif {
@@ -12,3 +11,15 @@
   pub device_id: String,
   pub payload: String,
 }
+
+/// FCM notif built on client.
+#[derive(Serialize, Deserialize, PartialEq, Debug)]
+#[serde(tag = "type", rename_all = "camelCase")]
+pub struct FCMNotif {
+  #[serde(rename = "clientMessageID")]
+  pub client_message_id: String,
+  #[serde(rename = "deviceID")]
+  pub device_id: String,
+  pub data: String,
+  pub priority: String,
+}