diff --git a/bindings/notifications.go b/bindings/notifications.go
index 7f393cf7271c253cf5e07771f9f570d89b69a3de..62cf55faea8eb127dddf116303a2153c41c16906 100644
--- a/bindings/notifications.go
+++ b/bindings/notifications.go
@@ -50,7 +50,7 @@ func (mnfmr *ManyNotificationForMeReport) Len() int {
 
 // NotificationsForMe Check if a notification received is for me
 // It returns a NotificationForMeReport which contains a ForMe bool stating if it is for the caller,
-// a Type, and a source. These are as follows:
+// a Tag, and a source. These are as follows:
 //	TYPE       	SOURCE				DESCRIPTION
 // 	"default"	recipient user ID	A message with no association
 //	"request"	sender user ID		A channel request has been received
diff --git a/event/event_test.go b/event/event_test.go
index 8be16a67ee3526b619907214953b277c8cc6226f..c960f1374b134f5635984a3571e154fb4e901291 100644
--- a/event/event_test.go
+++ b/event/event_test.go
@@ -35,7 +35,7 @@ func TestEventReporting(t *testing.T) {
 
 	// Send a few events
 	evtMgr.Report(10, "Hi", "TypityType", "I'm an event")
-	evtMgr.Report(1, "Hi", "TypeII", "Type II errors are the worst")
+	evtMgr.Report(1, "Hi", "TypeII", "Tag II errors are the worst")
 	evtMgr.Report(20, "Hi", "TypityType3", "eventy details")
 	evtMgr.Report(22, "Hi", "TypityType4", "I'm an event 2")
 
@@ -68,7 +68,7 @@ func TestEventReporting(t *testing.T) {
 	evtMgr.UnregisterEventCallback("test")
 	// Send more events
 	evtMgr.Report(10, "Hi", "TypityType", "I'm an event")
-	evtMgr.Report(1, "Hi", "TypeII", "Type II errors are the worst")
+	evtMgr.Report(1, "Hi", "TypeII", "Tag II errors are the worst")
 	evtMgr.Report(20, "Hi", "TypityType3", "eventy details")
 	evtMgr.Report(22, "Hi", "TypityType4", "I'm an event 2")
 
diff --git a/fileTransfer/ftMessages.pb.go b/fileTransfer/ftMessages.pb.go
index 4bc094d03ea4cd8e3776298f8c216972c286e45e..0663a60be474e3988c9efc4173ae74413da3257a 100644
--- a/fileTransfer/ftMessages.pb.go
+++ b/fileTransfer/ftMessages.pb.go
@@ -35,7 +35,7 @@ type NewFileTransfer struct {
 	unknownFields protoimpl.UnknownFields
 
 	FileName    string  `protobuf:"bytes,1,opt,name=fileName,proto3" json:"fileName,omitempty"`       // Name of the file; max 48 characters
-	FileType    string  `protobuf:"bytes,2,opt,name=fileType,proto3" json:"fileType,omitempty"`       // Type of file; max 8 characters
+	FileType    string  `protobuf:"bytes,2,opt,name=fileType,proto3" json:"fileType,omitempty"`       // Tag of file; max 8 characters
 	TransferKey []byte  `protobuf:"bytes,3,opt,name=transferKey,proto3" json:"transferKey,omitempty"` // 256 bit encryption key to identify the transfer
 	TransferMac []byte  `protobuf:"bytes,4,opt,name=transferMac,proto3" json:"transferMac,omitempty"` // 256 bit MAC of the entire file
 	NumParts    uint32  `protobuf:"varint,5,opt,name=numParts,proto3" json:"numParts,omitempty"`      // Number of file parts
diff --git a/go.mod b/go.mod
index 534fe473edd20876006fca0143f2e7a05240f0ff..101ca34e6f5c908e2573a5d837cc41d95b3ac97c 100644
--- a/go.mod
+++ b/go.mod
@@ -13,9 +13,9 @@ require (
 	github.com/spf13/viper v1.7.1
 	gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228
 	gitlab.com/elixxir/comms v0.0.4-0.20220308183624-c2183e687a03
-	gitlab.com/elixxir/crypto v0.0.7-0.20220325215559-7489d68d7714
+	gitlab.com/elixxir/crypto v0.0.7-0.20220328164108-c72388181116
 	gitlab.com/elixxir/ekv v0.1.6
-	gitlab.com/elixxir/primitives v0.0.3-0.20220222212109-d412a6e46623
+	gitlab.com/elixxir/primitives v0.0.3-0.20220325212708-5e2a7a385db7
 	gitlab.com/xx_network/comms v0.0.4-0.20220311192415-d95fe8906580
 	gitlab.com/xx_network/crypto v0.0.5-0.20220222212031-750f7e8a01f4
 	gitlab.com/xx_network/primitives v0.0.4-0.20220222211843-901fa4a2d72b
diff --git a/go.sum b/go.sum
index 8815f9a6d0b520caec5adad3455796ca70c3c58d..59dc6cb4ac92695cb2347125b6c174328fc3b3ed 100644
--- a/go.sum
+++ b/go.sum
@@ -281,6 +281,12 @@ gitlab.com/elixxir/crypto v0.0.7-0.20220309234716-1ba339865787 h1:+qmsWov412+Yn7
 gitlab.com/elixxir/crypto v0.0.7-0.20220309234716-1ba339865787/go.mod h1:tD6XjtQh87T2nKZL5I/pYPck5M2wLpkZ1Oz7H/LqO10=
 gitlab.com/elixxir/crypto v0.0.7-0.20220325215559-7489d68d7714 h1:epnov8zyFWod14MUNtGHSbZCVSkZjN4NvoiBs1TgEV8=
 gitlab.com/elixxir/crypto v0.0.7-0.20220325215559-7489d68d7714/go.mod h1:tD6XjtQh87T2nKZL5I/pYPck5M2wLpkZ1Oz7H/LqO10=
+gitlab.com/elixxir/crypto v0.0.7-0.20220325224306-705ce59288bb h1:WdlmG+KPaM2Pjo1EFiFFPYEVSMV64Di1CitQnXGWBOQ=
+gitlab.com/elixxir/crypto v0.0.7-0.20220325224306-705ce59288bb/go.mod h1:tD6XjtQh87T2nKZL5I/pYPck5M2wLpkZ1Oz7H/LqO10=
+gitlab.com/elixxir/crypto v0.0.7-0.20220328163237-3bdc3e1369ca h1:jPhotwqZFJYHR4LFitMSvkYtlYH9One+yTsEIoBwQCw=
+gitlab.com/elixxir/crypto v0.0.7-0.20220328163237-3bdc3e1369ca/go.mod h1:tD6XjtQh87T2nKZL5I/pYPck5M2wLpkZ1Oz7H/LqO10=
+gitlab.com/elixxir/crypto v0.0.7-0.20220328164108-c72388181116 h1:HvMO//NbadCiKGI10cdW98WimYf0YIudzQeUznYAgRQ=
+gitlab.com/elixxir/crypto v0.0.7-0.20220328164108-c72388181116/go.mod h1:tD6XjtQh87T2nKZL5I/pYPck5M2wLpkZ1Oz7H/LqO10=
 gitlab.com/elixxir/ekv v0.1.6 h1:M2hUSNhH/ChxDd+s8xBqSEKgoPtmE6hOEBqQ73KbN6A=
 gitlab.com/elixxir/ekv v0.1.6/go.mod h1:e6WPUt97taFZe5PFLPb1Dupk7tqmDCTQu1kkstqJvw4=
 gitlab.com/elixxir/primitives v0.0.0-20200731184040-494269b53b4d/go.mod h1:OQgUZq7SjnE0b+8+iIAT2eqQF+2IFHn73tOo+aV11mg=
@@ -289,6 +295,8 @@ gitlab.com/elixxir/primitives v0.0.0-20200804182913-788f47bded40/go.mod h1:tzdFF
 gitlab.com/elixxir/primitives v0.0.1/go.mod h1:kNp47yPqja2lHSiS4DddTvFpB/4D9dB2YKnw5c+LJCE=
 gitlab.com/elixxir/primitives v0.0.3-0.20220222212109-d412a6e46623 h1:NzJ06KdJd3fVJee0QvGhNr3CO+Ki8Ea1PeakZsm+rZM=
 gitlab.com/elixxir/primitives v0.0.3-0.20220222212109-d412a6e46623/go.mod h1:MtFIyJUQn9P7djzVlBpEYkPNnnWFTjZvw89swoXY+QM=
+gitlab.com/elixxir/primitives v0.0.3-0.20220325212708-5e2a7a385db7 h1:2yIEkxkPJboftkk/xiCONVP/FSl7Y3zOPpekvQ2dhO0=
+gitlab.com/elixxir/primitives v0.0.3-0.20220325212708-5e2a7a385db7/go.mod h1:MtFIyJUQn9P7djzVlBpEYkPNnnWFTjZvw89swoXY+QM=
 gitlab.com/xx_network/comms v0.0.0-20200805174823-841427dd5023/go.mod h1:owEcxTRl7gsoM8c3RQ5KAm5GstxrJp5tn+6JfQ4z5Hw=
 gitlab.com/xx_network/comms v0.0.4-0.20220223205228-7c4974139569/go.mod h1:isHnwem0v4rTcwwHP455FhVlFyPcHkHiVz+N3s/uCSI=
 gitlab.com/xx_network/comms v0.0.4-0.20220311192415-d95fe8906580 h1:IV0gDwdTxtCpc9Vkx7IeSStSqvG+0ZpF57X+OhTQDIM=
diff --git a/interfaces/networkManager.go b/interfaces/networkManager.go
index e39af97f8e2380b6aced6dcbd01ad7ec0d612b9e..4914bfb4fa04dd5273ea5bfb775ae1e3450b33ba 100644
--- a/interfaces/networkManager.go
+++ b/interfaces/networkManager.go
@@ -219,26 +219,6 @@ type NetworkManager interface {
 
 type Preimage [32]byte
 
-type Trigger struct {
-	Preimage
-	Type   string
-	Source []byte
-}
-
-type TriggerTracker func(triggers []Trigger)
-
-type MessageProcessor interface {
-	// Process decrypts and hands off the message to its internal down
-	// stream message processing system.
-	// CRITICAL: Fingerprints should never be used twice. Process must
-	// denote, in long term storage, usage of a fingerprint and that
-	// fingerprint must not be added again during application load.
-	// It is a security vulnerability to reuse a fingerprint. It leaks
-	// privacy and can lead to compromise of message contents and integrity.
-	Process(message format.Message, receptionID EphemeralIdentity,
-		round *mixmessages.RoundInfo)
-}
-
 type ClientErrorReport func(source, message, trace string)
 
 //type Ratchet interface {
diff --git a/storage/utility/cmixMessageBuffer.go b/network/cmixMessageBuffer.go
similarity index 92%
rename from storage/utility/cmixMessageBuffer.go
rename to network/cmixMessageBuffer.go
index e072f05d4bf1dbc7fab4ba5371c32ba786f63860..a70733ba44e7981be4a6fae8329a52c9227a7a52 100644
--- a/storage/utility/cmixMessageBuffer.go
+++ b/network/cmixMessageBuffer.go
@@ -5,12 +5,13 @@
 // LICENSE file                                                              //
 ///////////////////////////////////////////////////////////////////////////////
 
-package utility
+package network
 
 import (
 	"encoding/json"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/storage/utility"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
@@ -25,6 +26,7 @@ type cmixMessageHandler struct{}
 type storedMessage struct {
 	Msg       []byte
 	Recipient []byte
+	Params    []byte
 }
 
 func (sm storedMessage) Marshal() []byte {
@@ -79,12 +81,12 @@ func (cmh *cmixMessageHandler) DeleteMessage(kv *versioned.KV, key string) error
 }
 
 // HashMessage generates a hash of the message.
-func (cmh *cmixMessageHandler) HashMessage(m interface{}) MessageHash {
+func (cmh *cmixMessageHandler) HashMessage(m interface{}) utility.MessageHash {
 	h, _ := blake2b.New256(nil)
 
 	h.Write(m.(storedMessage).Marshal())
 
-	var messageHash MessageHash
+	var messageHash utility.MessageHash
 	copy(messageHash[:], h.Sum(nil))
 
 	return messageHash
@@ -93,11 +95,11 @@ func (cmh *cmixMessageHandler) HashMessage(m interface{}) MessageHash {
 // CmixMessageBuffer wraps the message buffer to store and load raw cmix
 // messages.
 type CmixMessageBuffer struct {
-	mb *MessageBuffer
+	mb *utility.MessageBuffer
 }
 
 func NewCmixMessageBuffer(kv *versioned.KV, key string) (*CmixMessageBuffer, error) {
-	mb, err := NewMessageBuffer(kv, &cmixMessageHandler{}, key)
+	mb, err := utility.NewMessageBuffer(kv, &cmixMessageHandler{}, key)
 	if err != nil {
 		return nil, err
 	}
@@ -106,7 +108,7 @@ func NewCmixMessageBuffer(kv *versioned.KV, key string) (*CmixMessageBuffer, err
 }
 
 func LoadCmixMessageBuffer(kv *versioned.KV, key string) (*CmixMessageBuffer, error) {
-	mb, err := LoadMessageBuffer(kv, &cmixMessageHandler{}, key)
+	mb, err := utility.LoadMessageBuffer(kv, &cmixMessageHandler{}, key)
 	if err != nil {
 		return nil, err
 	}
diff --git a/storage/utility/cmixMessageBuffer_test.go b/network/cmixMessageBuffer_test.go
similarity index 94%
rename from storage/utility/cmixMessageBuffer_test.go
rename to network/cmixMessageBuffer_test.go
index 48be053ea5b1ad01c571f6bd0c5cc26a9420fb7d..c8377dd9bf8fafc0d76cb95ac6508e21c52977cf 100644
--- a/storage/utility/cmixMessageBuffer_test.go
+++ b/network/cmixMessageBuffer_test.go
@@ -5,10 +5,11 @@
 // LICENSE file                                                              //
 ///////////////////////////////////////////////////////////////////////////////
 
-package utility
+package network
 
 import (
 	"bytes"
+	"gitlab.com/elixxir/client/storage/utility"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/elixxir/primitives/format"
@@ -31,7 +32,7 @@ func TestCmixMessageHandler_SaveMessage(t *testing.T) {
 			Msg:       testMsgs[i].Marshal(),
 			Recipient: ids[i].Marshal(),
 		}
-		key := MakeStoredMessageKey("testKey", cmh.HashMessage(msg))
+		key := utility.MakeStoredMessageKey("testKey", cmh.HashMessage(msg))
 
 		// Save message
 		err := cmh.SaveMessage(kv, msg, key)
@@ -67,7 +68,7 @@ func TestCmixMessageHandler_LoadMessage(t *testing.T) {
 			Msg:       testMsgs[i].Marshal(),
 			Recipient: ids[i].Marshal(),
 		}
-		key := MakeStoredMessageKey("testKey", cmh.HashMessage(msg))
+		key := utility.MakeStoredMessageKey("testKey", cmh.HashMessage(msg))
 
 		// Save message
 		if err := cmh.SaveMessage(kv, msg, key); err != nil {
@@ -157,10 +158,10 @@ func TestCmixMessageBuffer_Smoke(t *testing.T) {
 
 // makeTestCmixMessages creates a list of messages with random data and the
 // expected map after they are added to the buffer.
-func makeTestCmixMessages(n int) ([]format.Message, []*id.ID, map[MessageHash]struct{}) {
+func makeTestCmixMessages(n int) ([]format.Message, []*id.ID, map[utility.MessageHash]struct{}) {
 	cmh := &cmixMessageHandler{}
 	prng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
-	mh := map[MessageHash]struct{}{}
+	mh := map[utility.MessageHash]struct{}{}
 	msgs := make([]format.Message, n)
 	ids := make([]*id.ID, n)
 	for i := range msgs {
diff --git a/network/critical.go b/network/critical.go
new file mode 100644
index 0000000000000000000000000000000000000000..d838135bd4fe947b2a01a74a72b947e4b589d6c6
--- /dev/null
+++ b/network/critical.go
@@ -0,0 +1,13 @@
+package network
+
+import (
+	"gitlab.com/elixxir/client/network/health"
+)
+
+type Manager struct {
+	storage *CmixMessageBuffer
+	trigger chan bool
+	hm      *health.Monitor
+}
+
+func NewManager()
diff --git a/network/interface.go b/network/interface.go
index 0c48d254657515a5895c697343cdb981951ddabe..dd5b12290ac83e5d73b0e580fb5aa9824afcd5bb 100644
--- a/network/interface.go
+++ b/network/interface.go
@@ -1,7 +1,7 @@
 package network
 
 import (
-	"gitlab.com/elixxir/client/network/identity/receptionID"
+	"gitlab.com/elixxir/client/network/message"
 	"gitlab.com/elixxir/client/stoppable"
 	"gitlab.com/elixxir/comms/mixmessages"
 	"gitlab.com/elixxir/comms/network"
@@ -22,18 +22,55 @@ type Manager interface {
 
 	/*===Sending==============================================================*/
 
+	// GetMaxMessageLength returns the max message size for the current network
+	GetMaxMessageLength() int
+
 	// SendCMIX sends a "raw" CMIX message payload to the provided recipient.
 	// Returns the round ID of the round the payload was sent or an error
 	// if it fails.
+	// This does not have end to end encryption on it and is used exclusively as a
+	// send for higher order cryptographic protocols. Do not use unless implementing
+	// a protocol on top.
+	//   recipient - cMix ID of the recipient
+	//   fingerprint - Key Fingerprint. 256 bit field to store a 255 bit
+	//      fingerprint, highest order bit must be 0 (panic otherwise). If your
+	//      system does not use key fingerprints, this must be random bits.
+	//   service - Reception Service. The backup way for a client to identify
+	//      messages on receipt via trial hashing and to identify notifications.
+	//      If unused, use messages.RandomService to fill the field with random data
+	//   payload - Contents of the message. Cannot exceed the payload size for a
+	//      cMix message (panic otherwise).
+	//   mac - 256 bit field to store a 255 bit mac, highest order bit must be 0
+	//      (panic otherwise). If used, fill with random bits.
+	// Will return an error if the network is unhealthy or if it fails to send
+	// (along with the reason). Blocks until successful send or err.
+	// WARNING: Do not roll your own crypto
 	SendCMIX(message format.Message, recipient *id.ID, p CMIXParams) (
 		id.Round, ephemeral.Id, error)
 
-	// SendManyCMIX sends many "raw" cMix message payloads to each of the provided
-	// recipients. Used to send messages in group chats. Metadata is NOT as well
-	// protected with this call and can leak data about yourself. Should be
-	// replaced with multiple uses of SendCmix in most cases. Returns the round
-	// ID of the round the payload was sent or an error if it fails.
-	// WARNING: Potentially Unsafe
+	// SendManyCMIX sends many "raw" CMIX message payloads to the provided
+	// recipients all in the same round.
+	// Returns the round ID of the round the payloads was sent or an error
+	// if it fails.
+	// This does not have end to end encryption on it and is used exclusively as a
+	// send for higher order cryptographic protocols. Do not use unless implementing
+	// a protocol on top.
+	// Due to sending multiple payloads, this leaks more metadata than a standard
+	// cmix send and should be in general avoided.
+	//   recipient - cMix ID of the recipient
+	//   fingerprint - Key Fingerprint. 256 bit field to store a 255 bit
+	//      fingerprint, highest order bit must be 0 (panic otherwise). If your
+	//      system does not use key fingerprints, this must be random bits.
+	//   service - Reception Service. The backup way for a client to identify
+	//      messages on receipt via trial hashing and to identify notifications.
+	//      If unused, use messages.RandomService to fill the field with random data
+	//   payload - Contents of the message. Cannot exceed the payload size for a
+	//      cMix message (panic otherwise).
+	//   mac - 256 bit field to store a 255 bit mac, highest order bit must be 0
+	//      (panic otherwise). If used, fill with random bits.
+	// Will return an error if the network is unhealthy or if it fails to send
+	// (along with the reason). Blocks until successful send or err.
+	// WARNING: Do not roll your own crypto
 	SendManyCMIX(messages []TargetedCmixMessage, p CMIXParams) (
 		id.Round, []ephemeral.Id, error)
 
@@ -60,7 +97,7 @@ type Manager interface {
 	// AddFingerprint - Adds a fingerprint which will be handled by a
 	// specific processor for messages received by the given identity
 	AddFingerprint(identity *id.ID, fingerprint format.Fingerprint,
-		mp MessageProcessor) error
+		mp message.Processor) error
 
 	// DeleteFingerprint deletes a single fingerprint associated with the given
 	// identity if it exists
@@ -70,11 +107,11 @@ type Manager interface {
 	// identity if it exists
 	DeleteClientFingerprints(identity *id.ID)
 
-	/* trigger - predefined hash based tags appended to all cMix messages
+	/* Service - predefined hash based tags appended to all cMix messages
 	which, though trial hashing, are used to determine if a message applies
 	to this client
 
-	Triggers are used for 2 purposes - They can be processed by the
+	Services are used for 2 purposes - They can be processed by the
 	notifications system, or can be used to implement custom non fingerprint
 	processing of payloads. I.E. key negotiation, broadcast negotiation
 
@@ -85,41 +122,38 @@ type Manager interface {
 	messages are for the client on reception (which is normally hidden due to
 	collision between ephemeral IDs.
 
-	Due to the extra overhead of trial hashing, triggers are processed after fingerprints.
-	If a fingerprint match occurs on the message, triggers will not be handled.
+	Due to the extra overhead of trial hashing, services  are processed after
+	fingerprints. If a fingerprint match occurs on the message, services will
+	not be handled.
 
-	Triggers are address to the session. When starting a new client, all triggers must be
-	re-added before StartNetworkFollower is called.
+	Services are address to the session. When starting a new client, all
+	services must be re-added before StartNetworkFollower is called.
 	*/
 
-	// AddTrigger - Adds a trigger which can call a message handing function or
-	// be used for notifications. Multiple triggers can be registered for the
-	// same preimage.
+	// AddService adds a service which can call a message handing function or be
+	// used for notifications. In general a single service can only be registered
+	// for the same identifier/tag pair.
 	//   preimage - the preimage which is triggered on
-	//   type - a descriptive string of the trigger. Generally used in notifications
+	//   type - a descriptive string of the service. Generally used in notifications
 	//   source - a byte buffer of related data. Generally used in notifications.
 	//     Example: Sender ID
-	AddTrigger(identity *id.ID, newTrigger Trigger, response MessageProcessor)
+	AddService(AddService *id.ID, newService message.Service, response message.Processor)
 
-	// DeleteTrigger - If only a single response is associated with the
-	// preimage, the entire preimage is removed. If there is more than one
-	// response, only the given response is removed if nil is passed in for
-	// response, all triggers for the preimage will be removed
-	DeleteTrigger(identity *id.ID, preimage Preimage, response MessageProcessor) error
+	// DeleteService - If only a single response is associated with the preimage,
+	// the entire preimage is removed. If there is more than one response, only the
+	// given response is removed. If nil is passed in for response, all triggers for
+	// the preimage will be removed.
+	DeleteService(clientID *id.ID, toDelete message.Service, processor message.Processor)
 
-	// DeleteClientTriggers - deletes all triggers assoseated with the given identity
-	DeleteClientTriggers(identity *id.ID)
+	// DeleteClientService deletes the mapping associated with an ID.
+	DeleteClientService(clientID *id.ID)
 
-	// TrackTriggers - Registers a callback which will get called every time triggers change.
+	// TrackServices - Registers a callback which will get called every time a
+	// service is added or removed.
 	// It will receive the triggers list every time it is modified.
 	// Will only get callbacks while the Network Follower is running.
 	// Multiple trackTriggers can be registered
-	TrackTriggers(TriggerTracker)
-
-
-	//Dropped Messages Pickup
-	RegisterDroppedMessagesPickup(response MessageProcessor)
-	DenoteReception(msgId uint)
+	TrackServices(tracker message.ServicesTracker)
 
 	/* In inProcess */
 	// it is possible to receive a message over cMix before the fingerprints or
@@ -228,26 +262,4 @@ type Manager interface {
 	GetVerboseRounds() string
 }
 
-type Preimage [32]byte
-
-type Trigger struct {
-	Preimage
-	Type   string
-	Source []byte
-}
-
-type TriggerTracker func(triggers []Trigger)
-
-type MessageProcessor interface {
-	// Process decrypts and hands off the message to its internal down
-	// stream message processing system.
-	// CRITICAL: Fingerprints should never be used twice. Process must
-	// denote, in long term storage, usage of a fingerprint and that
-	// fingerprint must not be added again during application load.
-	// It is a security vulnerability to reuse a fingerprint. It leaks
-	// privacy and can lead to compromise of message contents and integrity.
-	Process(message format.Message, receptionID receptionID.EphemeralIdentity,
-		round *mixmessages.RoundInfo)
-}
-
 type ClientErrorReport func(source, message, trace string)
diff --git a/network/manager.go b/network/manager.go
index 5624c916d64a30a98082aab9657b8ead5eba19db..fd4cbc25b647a4fa287195881d72a8574a9b5e47 100644
--- a/network/manager.go
+++ b/network/manager.go
@@ -27,6 +27,7 @@ import (
 	"gitlab.com/elixxir/comms/client"
 	commNetwork "gitlab.com/elixxir/comms/network"
 	"gitlab.com/elixxir/crypto/fastRNG"
+	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/ndf"
 	"math"
@@ -80,6 +81,9 @@ type manager struct {
 
 	// Event reporting api
 	events event.Manager
+
+	//storage of the max message length
+	maxMsgLen int
 }
 
 // NewManager builds a new reception manager object using inputted key fields
@@ -94,6 +98,8 @@ func NewManager(params Params, comms *client.Comms, session storage.Session,
 			" client network manager")
 	}
 
+	tmpMsg := format.NewMessage(session.GetCmixGroup().GetP().ByteLen())
+
 	tracker := uint64(0)
 	earliest := uint64(0)
 	// create manager object
@@ -107,6 +113,7 @@ func NewManager(params Params, comms *client.Comms, session storage.Session,
 		rng:           rng,
 		comms:         comms,
 		instance:      instance,
+		maxMsgLen:     tmpMsg.ContentsSize(),
 	}
 	m.UpdateAddressSpace(18)
 
@@ -224,3 +231,8 @@ func (m *manager) GetVerboseRounds() string {
 func (m *manager) SetFakeEarliestRound(rnd id.Round) {
 	atomic.StoreUint64(m.earliestRound, uint64(rnd))
 }
+
+// GetMaxMessageLength returns the maximum length of a cmix message
+func (m *manager) GetMaxMessageLength() int {
+	return m.maxMsgLen
+}
diff --git a/network/message/bundle.go b/network/message/bundle.go
index b0ab15c22115fb8004dd7cb3154c9c206505b71c..a3fe68d783b106475ca9d79f77ac56234918c9e5 100644
--- a/network/message/bundle.go
+++ b/network/message/bundle.go
@@ -8,7 +8,7 @@
 package message
 
 import (
-	"gitlab.com/elixxir/client/interfaces"
+	"gitlab.com/elixxir/client/network/identity/receptionID"
 	pb "gitlab.com/elixxir/comms/mixmessages"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
@@ -19,5 +19,5 @@ type Bundle struct {
 	RoundInfo *pb.RoundInfo
 	Messages  []format.Message
 	Finish    func()
-	Identity  interfaces.EphemeralIdentity
+	Identity  receptionID.EphemeralIdentity
 }
diff --git a/network/message/fingerprints.go b/network/message/fingerprints.go
index 91fa906d4d1ff8cd0ebd0e760219c5fa493b7ee2..01b814470f85b3d1abe3fa2078ea8af0aa1de171 100644
--- a/network/message/fingerprints.go
+++ b/network/message/fingerprints.go
@@ -11,7 +11,6 @@ import (
 	"sync"
 
 	"github.com/pkg/errors"
-	"gitlab.com/elixxir/client/interfaces"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
 )
@@ -19,14 +18,14 @@ import (
 // FingerprintsManager is a thread-safe map, mapping format.Fingerprint's to
 // a Handler object.
 type FingerprintsManager struct {
-	fpMap map[id.ID]map[format.Fingerprint]interfaces.MessageProcessor
+	fpMap map[id.ID]map[format.Fingerprint]Processor
 	sync.Mutex
 }
 
 // newFingerprints is a constructor function for the Fingerprints tracker.
 func newFingerprints() *FingerprintsManager {
 	return &FingerprintsManager{
-		fpMap: make(map[id.ID]map[format.Fingerprint]interfaces.MessageProcessor),
+		fpMap: make(map[id.ID]map[format.Fingerprint]Processor),
 	}
 }
 
@@ -36,7 +35,7 @@ func newFingerprints() *FingerprintsManager {
 // vulnerability.
 func (f *FingerprintsManager) pop(clientID *id.ID,
 	fingerprint format.Fingerprint) (
-	interfaces.MessageProcessor, bool) {
+	Processor, bool) {
 	f.Lock()
 	defer f.Unlock()
 	cid := *clientID
@@ -58,7 +57,7 @@ func (f *FingerprintsManager) pop(clientID *id.ID,
 // value. If there is already an entry for this fingerprint, the
 // method returns with no write operation.
 func (f *FingerprintsManager) AddFingerprint(clientID *id.ID,
-	fingerprint format.Fingerprint, mp interfaces.MessageProcessor) error {
+	fingerprint format.Fingerprint, mp Processor) error {
 	f.Lock()
 	defer f.Unlock()
 
@@ -66,7 +65,7 @@ func (f *FingerprintsManager) AddFingerprint(clientID *id.ID,
 
 	if _, exists := f.fpMap[cid]; !exists {
 		f.fpMap[cid] = make(
-			map[format.Fingerprint]interfaces.MessageProcessor)
+			map[format.Fingerprint]Processor)
 	}
 
 	if _, exists := f.fpMap[cid][fingerprint]; exists {
diff --git a/network/message/handler.go b/network/message/handler.go
index 0496f71ab601a77f65df25812874b46c8c6fec9d..625a43b2dbe62bb0e20c75058611b98756f49a2a 100644
--- a/network/message/handler.go
+++ b/network/message/handler.go
@@ -10,10 +10,8 @@ package message
 import (
 	"fmt"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/interfaces"
 	"gitlab.com/elixxir/client/interfaces/preimage"
 	"gitlab.com/elixxir/client/stoppable"
-	fingerprint2 "gitlab.com/elixxir/crypto/fingerprint"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/netTime"
 	"sync"
@@ -65,21 +63,19 @@ func (p *handler) handleMessage(ecrMsg format.Message, bundle Bundle) bool {
 	identity := bundle.Identity
 	round := bundle.RoundInfo
 
-	var receptionID interfaces.EphemeralIdentity
-
 	// If we have a fingerprint, process it.
 	if proc, exists := p.pop(identity.Source, fingerprint); exists {
-		proc.Process(ecrMsg, receptionID, round)
+		proc.Process(ecrMsg, identity, round)
 		return true
 	}
 
 	triggers, exists := p.get(identity.Source, ecrMsg.GetSIH(), ecrMsg.GetContents())
 	if exists {
 		for _, t := range triggers {
-			go t.Process(ecrMsg, receptionID, round)
+			go t.Process(ecrMsg, identity, round)
 		}
 		if len(triggers) == 0 {
-			jww.ERROR.Printf("empty trigger list for %s",
+			jww.ERROR.Printf("empty service list for %s",
 				ecrMsg.GetSIH()) // get preimage
 		}
 		return true
@@ -91,17 +87,10 @@ func (p *handler) handleMessage(ecrMsg format.Message, bundle Bundle) bool {
 		// 	ecrMsgContents, preimage.MakeDefault(identity.Source))
 	}
 
-	if jww.GetLogThreshold() == jww.LevelTrace {
-		expectedFP := fingerprint2.IdentityFP(ecrMsg.GetContents(),
-			preimage.MakeDefault(identity.Source))
-		jww.TRACE.Printf("Message for %d (%s) failed identity "+
-			"check: %v (expected-default) vs %v (received)",
-			identity.EphId,
-			identity.Source, expectedFP, ecrMsg.GetSIH())
-	}
-	im := fmt.Sprintf("Garbled/RAW Message: keyFP: %v, round: %d"+
+	im := fmt.Sprintf("Message cannot be identify: keyFP: %v, round: %d"+
 		"msgDigest: %s, not determined to be for client",
 		ecrMsg.GetKeyFP(), bundle.Round, ecrMsg.Digest())
+	jww.TRACE.Printf(im)
 	p.events.Report(1, "MessageReception", "Garbled", im)
 	return false
 }
diff --git a/network/message/pickup.go b/network/message/pickup.go
index d86aa1a2f70464511dcfd3275ad439cdb267094e..7ad3173ad24b736500e67895df3f571ded08c1b0 100644
--- a/network/message/pickup.go
+++ b/network/message/pickup.go
@@ -9,7 +9,6 @@ package message
 
 import (
 	"gitlab.com/elixxir/client/event"
-	"gitlab.com/elixxir/client/interfaces"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
@@ -29,15 +28,15 @@ type Handler interface {
 	CheckInProgressMessages()
 
 	// Fingerprints
-	AddFingerprint(clientID *id.ID, fingerprint format.Fingerprint, mp interfaces.MessageProcessor) error
+	AddFingerprint(clientID *id.ID, fingerprint format.Fingerprint, mp Processor) error
 	DeleteFingerprint(clientID *id.ID, fingerprint format.Fingerprint)
 	DeleteClientFingerprints(clientID *id.ID)
 
 	// Triggers
-	AddTrigger(clientID *id.ID, newTrigger interfaces.Trigger, response interfaces.MessageProcessor)
-	DeleteTrigger(clientID *id.ID, preimage interfaces.Preimage, response interfaces.MessageProcessor) error
-	DeleteClientTriggers(clientID *id.ID)
-	TrackTriggers(triggerTracker interfaces.TriggerTracker)
+	AddService(clientID *id.ID, newService Service, response Processor)
+	DeleteService(clientID *id.ID, toDelete Service, response Processor)
+	DeleteClientService(clientID *id.ID)
+	TrackServices(triggerTracker ServicesTracker)
 }
 
 type handler struct {
@@ -51,7 +50,7 @@ type handler struct {
 	events event.Manager
 
 	FingerprintsManager
-	TriggersManager
+	ServicesManager
 }
 
 func NewHandler(param Params, kv *versioned.KV, events event.Manager) Handler {
@@ -70,7 +69,7 @@ func NewHandler(param Params, kv *versioned.KV, events event.Manager) Handler {
 	}
 
 	m.FingerprintsManager = *newFingerprints()
-	m.TriggersManager = *NewTriggers()
+	m.ServicesManager = *NewServices()
 	return &m
 }
 
diff --git a/network/message/processor.go b/network/message/processor.go
new file mode 100644
index 0000000000000000000000000000000000000000..f4aa5e3202615e3ed8f9328b8bcd44a3be3f2ade
--- /dev/null
+++ b/network/message/processor.go
@@ -0,0 +1,19 @@
+package message
+
+import (
+	"gitlab.com/elixxir/client/network/identity/receptionID"
+	"gitlab.com/elixxir/comms/mixmessages"
+	"gitlab.com/elixxir/primitives/format"
+)
+
+type Processor interface {
+	// Process decrypts and hands off the message to its internal down
+	// stream message processing system.
+	// CRITICAL: Fingerprints should never be used twice. Process must
+	// denote, in long term storage, usage of a fingerprint and that
+	// fingerprint must not be added again during application load.
+	// It is a security vulnerability to reuse a fingerprint. It leaks
+	// privacy and can lead to compromise of message contents and integrity.
+	Process(message format.Message, receptionID receptionID.EphemeralIdentity,
+		round *mixmessages.RoundInfo)
+}
diff --git a/network/message/serviceGenerators.go b/network/message/serviceGenerators.go
new file mode 100644
index 0000000000000000000000000000000000000000..c2e6c791e2787babf3238e76ef0896301e0b6fbd
--- /dev/null
+++ b/network/message/serviceGenerators.go
@@ -0,0 +1,37 @@
+package message
+
+import (
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/sih"
+	"gitlab.com/xx_network/crypto/csprng"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+// GetDefaultService is used to generate a default service. All identities
+// will respond to their default service, but it lacks privacy because it
+// uses the public ID as the key. Used for initial reach out in some protocols,
+// otherwise should not be used
+func GetDefaultService(recipient *id.ID) Service {
+	jww.WARN.Printf("Generating Default Service for %s - "+
+		"may not be private", recipient)
+	return Service{
+		Identifier: recipient[:],
+		Tag:        sih.Default,
+		Source:     recipient[:],
+	}
+}
+
+// GetRandomService is used to make a servivce for cMix sending when no
+// service is needed. It fills the Identifier with random, bits in order to
+// preserve privacy
+func GetRandomService(rng csprng.Source) Service {
+	identifier := make([]byte, 32)
+	if _, err := rng.Read(identifier); err != nil {
+		jww.FATAL.Panicf("Failed to generate random data: %+v", err)
+	}
+	return Service{
+		Identifier: identifier,
+		Tag:        "Random",
+		Source:     identifier,
+	}
+}
diff --git a/network/message/serviceInterface.go b/network/message/serviceInterface.go
new file mode 100644
index 0000000000000000000000000000000000000000..7c9e79d9027ae9362e38f5bdbac77864bb778b0c
--- /dev/null
+++ b/network/message/serviceInterface.go
@@ -0,0 +1,62 @@
+package message
+
+import (
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"gitlab.com/elixxir/crypto/sih"
+)
+
+type Service struct {
+	Identifier []byte
+	Tag        string
+	Source     []byte //optional metadata field, only used on reception
+
+	//private field for lazy evaluation of preimage
+	//Nil denotes not yet evaluated
+	lazyPreimage *sih.Preimage
+}
+
+func (si Service) Hash(contents []byte) []byte {
+	preimage := si.preimage()
+	return sih.Hash(preimage, contents)
+}
+
+func (si Service) HashFromMessageHash(messageHash []byte) []byte {
+	preimage := si.preimage()
+	return sih.HashFromMessageHash(preimage, messageHash)
+}
+
+func (si Service) preimage() sih.Preimage {
+	// calculate
+	if si.lazyPreimage == nil {
+		p := sih.MakePreimage(si.Identifier, si.Tag)
+		si.lazyPreimage = &p
+	}
+
+	return *si.lazyPreimage
+}
+
+func (si Service) ForMe(contents, hash []byte) bool {
+	return sih.ForMe(si.preimage(), contents, hash)
+}
+
+func (si Service) ForMeFromMessageHash(messageHash, hash []byte) bool {
+	return sih.ForMeFromMessageHash(si.preimage(), messageHash, hash)
+}
+
+func (si Service) MarshalJSON() ([]byte, error) {
+	return json.Marshal(&si)
+}
+
+func (si Service) UnmarshalJSON(b []byte) error {
+	return json.Unmarshal(b, &si)
+}
+
+func (si Service) String() string {
+	p := si.preimage()
+	return fmt.Sprintf("Tag: %s, Identifier: %s, source: %s, "+
+		"preimage:%s", si.Tag, base64.StdEncoding.EncodeToString(si.Identifier),
+		base64.StdEncoding.EncodeToString(si.Source),
+		base64.StdEncoding.EncodeToString(p[:]))
+}
diff --git a/network/message/serviceTracker.go b/network/message/serviceTracker.go
new file mode 100644
index 0000000000000000000000000000000000000000..8ae97c829f3218a3d6c60532dadde1e4e0412fe7
--- /dev/null
+++ b/network/message/serviceTracker.go
@@ -0,0 +1,72 @@
+package message
+
+import (
+	"encoding/json"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+type ServicesTracker func(ServiceList)
+
+// TrackServices adds a service tracker to be triggered when a nee service
+// as added. Generally used for notificatiosn to use this system to identify a
+// received message
+func (sm *ServicesManager) TrackServices(tracker ServicesTracker) {
+	if tracker == nil {
+		return
+	}
+	sm.Lock()
+	defer sm.Unlock()
+
+	sm.trackers = append(sm.trackers, tracker)
+}
+
+// triggerServiceTracking triggers the tracking of services.
+// Is it called when a service is added or removed.
+func (sm *ServicesManager) triggerServiceTracking() {
+	if len(sm.trackers) == 0 {
+		return
+	}
+
+	services := make(ServiceList)
+	for uid, tmap := range sm.tmap {
+		tList := make([]Service, 0, len(tmap))
+		for _, s := range tmap {
+			tList = append(tList, s.Service)
+		}
+		services[uid] = tList
+	}
+
+	for _, callback := range sm.trackers {
+		go callback(services)
+	}
+}
+
+// The ServiceList holds all services.
+type ServiceList map[id.ID][]Service
+
+type slMarshled struct {
+	Id       id.ID
+	Services []Service
+}
+
+func (sl ServiceList) MarshalJSON() ([]byte, error) {
+	slList := make([]slMarshled, 0, len(sl))
+	for uid, s := range sl {
+		slList = append(slList, slMarshled{
+			Id:       uid,
+			Services: s,
+		})
+	}
+	return json.Marshal(&slList)
+}
+
+func (sl ServiceList) UnmarshalJSON(b []byte) error {
+	slList := make([]slMarshled, 0)
+	if err := json.Unmarshal(b, &slList); err != nil {
+		return err
+	}
+	for _, s := range slList {
+		sl[s.Id] = s.Services
+	}
+	return nil
+}
diff --git a/network/message/services.go b/network/message/services.go
new file mode 100644
index 0000000000000000000000000000000000000000..987a1d3974d782ef0520aadfcb8ecc95186eba2a
--- /dev/null
+++ b/network/message/services.go
@@ -0,0 +1,184 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package message
+
+import (
+	"bytes"
+	jww "github.com/spf13/jwalterweatherman"
+	"sync"
+
+	"gitlab.com/elixxir/crypto/sih"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+/* Service Identification Hash - predefined hash based tags appended to
+all cMix messages which,though trial hashing, are used to determine if a message
+applies to this client.
+
+Services are used for 2 purposes - can be processed by the notification system,
+or can be used to implement custom non fingerprint processing of payloads (i.e.
+key negotiation and broadcast negotiation).
+
+A tag is appended to the message of the format tag = H(H(messageContents),preimage)
+and trial hashing is used to determine if a message adheres to a tag.
+WARNING: If a preimage is known by an adversary, they can determine which
+messages are for the client.
+
+Due to the extra overhead of trial hashing, services are processed after
+fingerprints. If a fingerprint match occurs on the message, triggers will not be
+handled.
+
+Services are address to the session. When starting a new client, all triggers
+must be re-added before StartNetworkFollower is called.
+*/
+
+type ServicesManager struct {
+	tmap        map[id.ID]map[sih.Preimage]service
+	trackers    []ServicesTracker
+	numServices uint
+	sync.Mutex
+}
+
+type service struct {
+	Service
+	Processor
+	defaultList []Processor
+}
+
+func NewServices() *ServicesManager {
+	// todo: implement me
+	return &ServicesManager{
+		tmap: make(map[id.ID]map[sih.Preimage]service),
+	}
+}
+
+// Lookup will see if a service exists for the given preimage and message
+// contents. It will do this by trial hashing the preimages in the map with the
+// received message contents, until either a match to the received identity
+// fingerprint is received or it has exhausted the map.
+// If a match is found, this means the message received is for the client, and
+// that one or multiple services exist to process this message.
+// These services are returned to the caller along with the a true boolean.
+// If the map has been exhausted with no matches found, it returns nil and false.
+func (sm *ServicesManager) get(clientID *id.ID, receivedSIH,
+	ecrMsgContents []byte) ([]Processor,
+	bool) {
+	sm.Lock()
+	defer sm.Unlock()
+	cid := *clientID
+
+	services, exists := sm.tmap[cid]
+	if !exists {
+		return nil, false
+	}
+	for _, s := range services {
+		// check if the sih matches this service
+		if s.ForMe(ecrMsgContents, receivedSIH) {
+			// return this service directly if not the default service
+			if s.defaultList == nil && s.Tag != sih.Default {
+				return []Processor{s}, true
+				// if it is default, and the default list isn't empty,
+				// return the default list
+			} else if s.defaultList != nil {
+				return s.defaultList, true
+			}
+			// return false if its for me but i have nothing registered to
+			// respond to default queries
+			return []Processor{}, false
+		}
+	}
+
+	return nil, false
+}
+
+// AddService adds a service which can call a message handing function or be
+// used for notifications. In general a single service can only be registered
+// for the same identifier/tag pair.
+//   preimage - the preimage which is triggered on
+//   type - a descriptive string of the service. Generally used in notifications
+//   source - a byte buffer of related data. Generally used in notifications.
+//     Example: Sender ID
+func (sm *ServicesManager) AddService(clientID *id.ID, newService Service,
+	response Processor) {
+	sm.Lock()
+	defer sm.Unlock()
+
+	newEntry := service{
+		Service:     newService,
+		Processor:   response,
+		defaultList: nil,
+	}
+
+	if newService.Tag == sih.Default {
+		if !bytes.Equal(newService.Identifier, clientID[:]) {
+			jww.FATAL.Panicf("Cannot accept a malformed 'Default' " +
+				"service, Identifier must match clientID")
+		}
+		oldDefault, exists := sm.tmap[*clientID][newService.preimage()]
+		if exists {
+			newEntry = oldDefault
+			oldDefault.defaultList = append(oldDefault.defaultList, response)
+		} else {
+			newEntry.Source = clientID[:]
+		}
+	} else if _, exists := sm.tmap[*clientID][newService.preimage()]; exists {
+		jww.FATAL.Panicf("Cannot add service %s, an identical "+
+			"service already exists", newService.Tag)
+	}
+
+	sm.tmap[*clientID][newService.preimage()] = newEntry
+
+	sm.numServices++
+	sm.triggerServiceTracking()
+}
+
+// DeleteService - If only a single response is associated with the preimage,
+// the entire preimage is removed. If there is more than one response, only the
+// given response is removed. If nil is passed in for response, all triggers for
+// the preimage will be removed.
+func (sm *ServicesManager) DeleteService(clientID *id.ID, toDelete Service,
+	processor Processor) {
+	sm.Lock()
+	defer sm.Unlock()
+	cid := *clientID
+
+	idTmap, exists := sm.tmap[cid]
+	if !exists {
+		return
+	}
+
+	services, exists := idTmap[toDelete.preimage()]
+	if !exists {
+		return
+	}
+
+	// do unique handling if this is a default service and there is more
+	// then one registered
+	if services.defaultList != nil && len(services.defaultList) > 1 {
+		for i, p := range services.defaultList {
+			if p == processor {
+				services.defaultList = append(services.defaultList[:i], services.defaultList[i+1:]...)
+				idTmap[toDelete.preimage()] = services
+				return
+			}
+		}
+	}
+
+	delete(idTmap, toDelete.preimage())
+	sm.numServices--
+	sm.triggerServiceTracking()
+	return
+}
+
+// DeleteClientService deletes the mapping associated with an ID.
+func (sm *ServicesManager) DeleteClientService(clientID *id.ID) {
+	sm.Lock()
+	defer sm.Unlock()
+
+	delete(sm.tmap, *clientID)
+}
diff --git a/network/message/triggers.go b/network/message/triggers.go
deleted file mode 100644
index ab733cdd334ab38943427173898a32f553766e5c..0000000000000000000000000000000000000000
--- a/network/message/triggers.go
+++ /dev/null
@@ -1,220 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package message
-
-import (
-	"golang.org/x/crypto/blake2b"
-	"sync"
-
-	"github.com/pkg/errors"
-	"gitlab.com/elixxir/client/interfaces"
-	"gitlab.com/elixxir/crypto/fingerprint"
-	"gitlab.com/xx_network/primitives/id"
-)
-
-/* Trigger - predefined hash based tags appended to all cMix messages which,
-though trial hashing, are used to determine if a message applies to this client.
-
-Triggers are used for 2 purposes - can be processed by the notification system,
-or can be used to implement custom non fingerprint processing of payloads (i.e.
-key negotiation and broadcast negotiation).
-
-A tag is appended to the message of the format tag = H(H(messageContents),preimage)
-and trial hashing is used to determine if a message adheres to a tag.
-WARNING: If a preimage is known by an adversary, they can determine which
-messages are for the client.
-
-Due to the extra overhead of trial hashing, triggers are processed after
-fingerprints. If a fingerprint match occurs on the message, triggers will not be
-handled.
-
-Triggers are address to the session. When starting a new client, all triggers
-must be re-added before StartNetworkFollower is called.
-*/
-
-type TriggersManager struct {
-	tmap        map[id.ID]map[interfaces.Preimage][]trigger
-	trackers    []interfaces.TriggerTracker
-	numTriggers uint
-	sync.Mutex
-}
-
-type trigger struct {
-	interfaces.Trigger
-	interfaces.MessageProcessor
-}
-
-func NewTriggers() *TriggersManager {
-	// todo: implement me
-	return &TriggersManager{
-		tmap: make(map[id.ID]map[interfaces.Preimage][]trigger, 0),
-	}
-}
-
-// Lookup will see if a trigger exists for the given preimage and message
-// contents. It will do this by trial hashing the preimages in the map with the
-// received message contents, until either a match to the received identity
-// fingerprint is received or it has exhausted the map.
-// If a match is found, this means the message received is for the client, and
-// that one or multiple triggers exist to process this message.
-// These triggers are returned to the caller along with the a true boolean.
-// If the map has been exhausted with no matches found, it returns nil and false.
-func (t *TriggersManager) get(clientID *id.ID, receivedIdentityFp,
-	ecrMsgContents []byte) ([]trigger,
-	bool) {
-	t.Lock()
-	defer t.Unlock()
-	cid := *clientID
-
-	triggers, exists := t.tmap[cid]
-	if !exists {
-		return nil, false
-	}
-
-	for pi, triggerList := range triggers {
-		if fingerprint.CheckIdentityFP(receivedIdentityFp,
-			ecrMsgContents, pi[:]) {
-			return triggerList, true
-		}
-	}
-
-	return nil, false
-}
-
-// AddTrigger adds a trigger which can call a message handing function or be
-// used for notifications. Multiple triggers can be registered for the same
-// preimage.
-//   preimage - the preimage which is triggered on
-//   type - a descriptive string of the trigger. Generally used in notifications
-//   source - a byte buffer of related data. Generally used in notifications.
-//     Example: Sender ID
-func (t *TriggersManager) AddTrigger(clientID *id.ID, newTrigger interfaces.Trigger,
-	response interfaces.MessageProcessor) {
-	t.Lock()
-	defer t.Unlock()
-
-	newEntry := trigger{
-		Trigger:          newTrigger,
-		MessageProcessor: response,
-	}
-
-	realTrigger := Generate(newTrigger.Preimage,newTrigger.Type)
-
-	cid := *clientID
-	if _, exists := t.tmap[cid]; !exists {
-		t.tmap[cid] = make(map[interfaces.Preimage][]trigger)
-	}
-
-
-	if existingTriggers, exists := t.tmap[cid][realTrigger]; exists {
-		t.tmap[cid][realTrigger] = append(existingTriggers, newEntry)
-	}
-
-	t.tmap[cid][realTrigger] = []trigger{newEntry}
-
-	t.numTriggers++
-	t.triggerTracking()
-}
-
-func Generate(data []byte, t string) []byte {
-	if t == Default {
-		return data
-	}
-	// Hash fingerprints
-	h, _ := blake2b.New256(nil)
-	h.Write(data)
-	h.Write([]byte(t))
-
-	// Base 64 encode hash and truncate
-	return h.Sum(nil)
-}
-
-// DeleteTrigger - If only a single response is associated with the preimage,
-// the entire preimage is removed. If there is more than one response, only the
-// given response is removed. If nil is passed in for response, all triggers for
-// the preimage will be removed.
-func (t *TriggersManager) DeleteTrigger(clientID *id.ID, preimage interfaces.Preimage,
-	response interfaces.MessageProcessor) error {
-	t.Lock()
-	defer t.Unlock()
-
-	if response == nil {
-		return errors.Errorf("response cannot be nil when deleting")
-	}
-
-	cid := *clientID
-
-	idTmap, exists := t.tmap[cid]
-	if !exists {
-		return nil
-	}
-
-	triggers, exists := idTmap[preimage]
-	if !exists {
-		return nil
-	}
-
-	if len(triggers) == 1 && triggers[0].MessageProcessor == response {
-		if len(idTmap) == 1 {
-			delete(t.tmap, cid)
-		} else {
-			delete(t.tmap[cid], preimage)
-		}
-	}
-
-	for idx, cur := range triggers {
-		if cur.MessageProcessor == response {
-			t.tmap[cid][preimage] = append(triggers[:idx],
-				triggers[idx+1:]...)
-			return nil
-		}
-	}
-	t.numTriggers--
-	t.triggerTracking()
-	return nil
-}
-
-// DeleteClientTriggers deletes the mapping associated with an ID.
-func (t *TriggersManager) DeleteClientTriggers(clientID *id.ID) {
-	t.Lock()
-	defer t.Unlock()
-
-	delete(t.tmap, *clientID)
-}
-
-// TrackTriggers adds a trigger tracker to be triggered when a nee trigger
-// as added.
-func (t *TriggersManager) TrackTriggers(triggerTracker interfaces.TriggerTracker) {
-	if triggerTracker == nil {
-		return
-	}
-	t.Lock()
-	defer t.Unlock()
-
-	t.trackers = append(t.trackers, triggerTracker)
-}
-
-//triggerTracking triggers the tracking of triggers
-func (t *TriggersManager) triggerTracking() {
-	if len(t.trackers) == 0 {
-		return
-	}
-
-	triggers := make([]interfaces.Trigger, 0, t.numTriggers)
-	for _, tmap := range t.tmap {
-		for _, tlist := range tmap {
-			for i := range tlist {
-				triggers = append(triggers, tlist[i].Trigger)
-			}
-		}
-	}
-
-	for _, callback := range t.trackers {
-		go callback(triggers)
-	}
-}
diff --git a/network/sendCmix.go b/network/sendCmix.go
index 0351f7685e8f23c6585aba876177df4fac022df1..592e24eedb527bb53dd92c9ed079719f39b54734 100644
--- a/network/sendCmix.go
+++ b/network/sendCmix.go
@@ -12,8 +12,8 @@ import (
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/event"
-	"gitlab.com/elixxir/client/interfaces"
 	"gitlab.com/elixxir/client/network/gateway"
+	"gitlab.com/elixxir/client/network/message"
 	"gitlab.com/elixxir/client/network/nodes"
 	"gitlab.com/elixxir/client/stoppable"
 	pb "gitlab.com/elixxir/comms/mixmessages"
@@ -32,55 +32,41 @@ import (
 	"time"
 )
 
-
-type StandardSendable struct{
-	Recipient *id.ID
-	Payload []byte
-	Fingerprint format.Fingerprint
-	Trigger StandardTrigger
-}
-
-type StandardTrigger struct{
-	Preimage
-	Type   string
-	Source []byte
-	crystal []byte
-}
-
-func (t *trigger)Crystalize()[]byte{
-	if t.crystal==nil{
-		t.crystal=t.generate()
-	}
-	return copy(t.crystal)
-}
-
-type Sendable interface{
-	GetRecipient()*id.ID
-	GetPayload()[]byte
-	GetMac()[]byte
-	GetFingerprint()format.Fingerprint
-	GetTriggerPreimage()PreimagePrefix
-}
-
-type Trigger interface{
-	GetPreimage()[]byte
-	GetSource()format.Fingerprint
-	GetType()string
-	Crystalize()[]byte
-}
-
-
 // SendCMIX sends a "raw" CMIX message payload to the provided recipient.
 // Returns the round ID of the round the payload was sent or an error
 // if it fails.
-func (m *manager) SendCMIX(message Sendable, cmixParams CMIXParams) (id.Round, ephemeral.Id, error) {
+// This does not have end to end encryption on it and is used exclusively as a
+// send for higher order cryptographic protocols. Do not use unless implementing
+// a protocol on top.
+//   recipient - cMix ID of the recipient
+//   fingerprint - Key Fingerprint. 256 bit field to store a 255 bit
+//      fingerprint, highest order bit must be 0 (panic otherwise). If your
+//      system does not use key fingerprints, this must be random bits.
+//   service - Reception Service. The backup way for a client to identify
+//      messages on receipt via trial hashing and to identify notifications.
+//      If unused, use messages.RandomService to fill the field with random data
+//   payload - Contents of the message. Cannot exceed the payload size for a
+//      cMix message (panic otherwise).
+//   mac - 256 bit field to store a 255 bit mac, highest order bit must be 0
+//      (panic otherwise). If used, fill with random bits.
+// Will return an error if the network is unhealthy or if it fails to send
+// (along with the reason). Blocks until successful send or err.
+// WARNING: Do not roll your own crypto
+func (m *manager) SendCMIX(recipient *id.ID, fingerprint format.Fingerprint, service message.Service,
+	payload, mac []byte, cmixParams CMIXParams) (id.Round, ephemeral.Id, error) {
 	if !m.Monitor.IsHealthy() {
 		return 0, ephemeral.Id{}, errors.New("Cannot send cmix message when the " +
 			"network is not healthy")
 	}
 
-	msgCopy := msg.Copy()
-	return sendCmixHelper(m.Sender, msgCopy, recipient, cmixParams, m.instance,
+	//Build message. Will panic if inputs are not correct.
+	msg := format.NewMessage(m.session.GetCmixGroup().GetP().ByteLen())
+	msg.SetKeyFP(fingerprint)
+	msg.SetContents(payload)
+	msg.SetMac(mac)
+	msg.SetSIH(service.Hash(msg.GetContents()))
+
+	return sendCmixHelper(m.Sender, msg, recipient, cmixParams, m.instance,
 		m.session.GetCmixGroup(), m.Registrar, m.rng, m.events,
 		m.session.GetTransmissionID(), m.comms)
 }
@@ -184,7 +170,7 @@ func sendCmixHelper(sender gateway.Sender, msg format.Message,
 		// Build the messages to send
 
 		wrappedMsg, encMsg, ephID, err := buildSlotMessage(msg, recipient,
-			firstGateway, stream, senderId, bestRound, roundKeys, cmixParams)
+			firstGateway, stream, senderId, bestRound, roundKeys)
 		if err != nil {
 			return 0, ephemeral.Id{}, err
 		}
diff --git a/network/sendCmixUtils.go b/network/sendCmixUtils.go
index 941ef57aa042cab07b922dcce63f1cc9f3465181..18c629e7fde1ab59cb146319f3e566e68655ddb1 100644
--- a/network/sendCmixUtils.go
+++ b/network/sendCmixUtils.go
@@ -10,12 +10,10 @@ package network
 import (
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
-	preimage2 "gitlab.com/elixxir/client/interfaces/preimage"
 	"gitlab.com/elixxir/client/network/nodes"
 	pb "gitlab.com/elixxir/comms/mixmessages"
 	"gitlab.com/elixxir/comms/network"
 	"gitlab.com/elixxir/crypto/fastRNG"
-	"gitlab.com/elixxir/crypto/fingerprint"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/elixxir/primitives/states"
 	"gitlab.com/xx_network/comms/connect"
@@ -112,7 +110,7 @@ func processRound(nodes nodes.Registrar, bestRound *pb.RoundInfo,
 // the recipient.
 func buildSlotMessage(msg format.Message, recipient *id.ID, target *id.ID,
 	stream *fastRNG.Stream, senderId *id.ID, bestRound *pb.RoundInfo,
-	mixCrypt nodes.MixCypher, param CMIXParams) (*pb.GatewaySlot,
+	mixCrypt nodes.MixCypher) (*pb.GatewaySlot,
 	format.Message, ephemeral.Id,
 	error) {
 
@@ -133,22 +131,6 @@ func buildSlotMessage(msg format.Message, recipient *id.ID, target *id.ID,
 
 	msg.SetEphemeralRID(ephIdFilled[:])
 
-	// use the alternate identity preimage if it is set
-	var preimage []byte
-	if param.IdentityPreimage != nil {
-		preimage = param.IdentityPreimage
-		jww.INFO.Printf("Sending to %s with override preimage %v", recipient, preimage)
-	} else {
-		preimage = preimage2.MakeDefault(recipient)
-		jww.INFO.Printf("Sending to %s with default preimage %v", recipient, preimage)
-	}
-
-	// Set the identity fingerprint
-
-	ifp := fingerprint.IdentityFP(msg.GetContents(), preimage)
-
-	msg.SetIdentityFP(ifp)
-
 	// Encrypt the message
 	salt := make([]byte, 32)
 	_, err = stream.Read(salt)
@@ -209,7 +191,7 @@ func handleMissingNodeKeys(instance *network.Instance,
 // string of comma seperated recipient IDs and a string of comma seperated
 // message digests. Duplicate recipient IDs are printed once. Intended for use
 // in printing to log.
-func messageListToStrings(msgList []TargetedCmixMessage) (string, string) {
+func messageListToStrings(msgList []assembeledCmixMessage) (string, string) {
 	idStrings := make([]string, 0, len(msgList))
 	idMap := make(map[id.ID]bool, len(msgList))
 	msgDigests := make([]string, len(msgList))
diff --git a/network/sendManyCmix.go b/network/sendManyCmix.go
index ad2ee803ba9ec49f3a2dbb2a825f3028a58c96b9..307062798f5b86326e1525c64b07ffe7ebe9a524 100644
--- a/network/sendManyCmix.go
+++ b/network/sendManyCmix.go
@@ -13,6 +13,7 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/event"
 	"gitlab.com/elixxir/client/network/gateway"
+	"gitlab.com/elixxir/client/network/message"
 	"gitlab.com/elixxir/client/network/nodes"
 	"gitlab.com/elixxir/client/stoppable"
 	pb "gitlab.com/elixxir/comms/mixmessages"
@@ -33,15 +34,36 @@ import (
 // TargetedCmixMessage defines a recipient target pair in a sendMany cMix
 // message.
 type TargetedCmixMessage struct {
-	Recipient *id.ID
-	Message   format.Message
+	Recipient   *id.ID
+	Payload     []byte
+	Fingerprint format.Fingerprint
+	Service     message.Service
+	Mac         []byte
 }
 
-// SendManyCMIX sends many "raw" cMix message payloads to each of the provided
-// recipients. Used to send messages in group chats. Metadata is NOT protected
-// with this call and can leak data about yourself. Returns the round ID of the
-// round the payload was sent or an error if it fails.
-// WARNING: Potentially Unsafe
+// SendManyCMIX sends many "raw" CMIX message payloads to the provided
+// recipients all in the same round.
+// Returns the round ID of the round the payloads was sent or an error
+// if it fails.
+// This does not have end to end encryption on it and is used exclusively as a
+// send for higher order cryptographic protocols. Do not use unless implementing
+// a protocol on top.
+// Due to sending multiple payloads, this leaks more metadata than a standard
+// cmix send and should be in general avoided.
+//   recipient - cMix ID of the recipient
+//   fingerprint - Key Fingerprint. 256 bit field to store a 255 bit
+//      fingerprint, highest order bit must be 0 (panic otherwise). If your
+//      system does not use key fingerprints, this must be random bits.
+//   service - Reception Service. The backup way for a client to identify
+//      messages on receipt via trial hashing and to identify notifications.
+//      If unused, use messages.RandomService to fill the field with random data
+//   payload - Contents of the message. Cannot exceed the payload size for a
+//      cMix message (panic otherwise).
+//   mac - 256 bit field to store a 255 bit mac, highest order bit must be 0
+//      (panic otherwise). If used, fill with random bits.
+// Will return an error if the network is unhealthy or if it fails to send
+// (along with the reason). Blocks until successful send or err.
+// WARNING: Do not roll your own crypto
 func (m *manager) SendManyCMIX(messages []TargetedCmixMessage,
 	p CMIXParams) (id.Round, []ephemeral.Id, error) {
 	if !m.Monitor.IsHealthy() {
@@ -49,11 +71,30 @@ func (m *manager) SendManyCMIX(messages []TargetedCmixMessage,
 			"message when the network is not healthy")
 	}
 
-	return sendManyCmixHelper(m.Sender, messages, p,
+	acms := make([]assembeledCmixMessage, len(messages))
+	for i := range messages {
+		msg := format.NewMessage(m.session.GetCmixGroup().GetP().ByteLen())
+		msg.SetKeyFP(messages[i].Fingerprint)
+		msg.SetContents(messages[i].Payload)
+		msg.SetMac(messages[i].Mac)
+		msg.SetSIH(messages[i].Service.Hash(msg.GetContents()))
+
+		acms[i] = assembeledCmixMessage{
+			Recipient: messages[i].Recipient,
+			Message:   msg,
+		}
+	}
+
+	return sendManyCmixHelper(m.Sender, acms, p,
 		m.instance, m.session.GetCmixGroup(), m.Registrar, m.rng, m.events,
 		m.session.GetTransmissionID(), m.comms)
 }
 
+type assembeledCmixMessage struct {
+	Recipient *id.ID
+	Message   format.Message
+}
+
 // sendManyCmixHelper is a helper function for manager.SendManyCMIX.
 //
 // NOTE: Payloads sent are not end-to-end encrypted, metadata is NOT protected
@@ -66,7 +107,7 @@ func (m *manager) SendManyCMIX(messages []TargetedCmixMessage,
 // which can be registered with the network instance to get a callback on its
 // status.
 func sendManyCmixHelper(sender gateway.Sender,
-	msgs []TargetedCmixMessage, param CMIXParams, instance *network.Instance,
+	msgs []assembeledCmixMessage, param CMIXParams, instance *network.Instance,
 	grp *cyclic.Group, registrar nodes.Registrar,
 	rng *fastRNG.StreamGenerator, events event.Manager,
 	senderId *id.ID, comms SendCmixCommsInterface) (
@@ -157,7 +198,7 @@ func sendManyCmixHelper(sender gateway.Sender,
 		for i, msg := range msgs {
 			slots[i], encMsgs[i], ephemeralIDs[i], err = buildSlotMessage(
 				msg.Message, msg.Recipient, firstGateway, stream, senderId,
-				bestRound, roundKeys, param)
+				bestRound, roundKeys)
 			if err != nil {
 				stream.Close()
 				jww.INFO.Printf("[SendManyCMIX-%s]error building slot received: %v", param.DebugTag, err)
diff --git a/storage/auth/store.go b/storage/auth/store.go
index f0a48c6d7dd1c80b19d6c11aac046bb4da9a209d..9a4580333a1b191a87958a73d391e6a5d98f93ce 100644
--- a/storage/auth/store.go
+++ b/storage/auth/store.go
@@ -397,7 +397,7 @@ func (s *Store) GetRequest(partner *id.ID) (RequestType, *SentRequest, contact.C
 		return Receive, nil, *r.receive, nil
 	default:
 		return 0, nil, contact.Contact{},
-			errors.Errorf("invalid Type: %d", r.rt)
+			errors.Errorf("invalid Tag: %d", r.rt)
 	}
 }
 
diff --git a/storage/e2e/manager.go b/storage/e2e/manager.go
index ff76e9985b72ef1c355be64ee0f643e1c07c3205..610c1b75f2e2c273f745e0824ad60325aae1462d 100644
--- a/storage/e2e/manager.go
+++ b/storage/e2e/manager.go
@@ -197,7 +197,7 @@ func (m *Manager) GetKeyForSending(st params.SendType) (*Key, error) {
 	default:
 	}
 
-	return nil, errors.Errorf("Cannot get session for invalid Send Type: %s", st)
+	return nil, errors.Errorf("Cannot get session for invalid Send Tag: %s", st)
 }
 
 // GetPartnerID returns a copy of the ID of the partner.
diff --git a/storage/utility/sidh_test.go b/storage/utility/sidh_test.go
index 13b557c493c277a7f292d99e8cf293ad8f3d6583..34ab3c43cfa84ee85de99fa3dff357e44dec244d 100644
--- a/storage/utility/sidh_test.go
+++ b/storage/utility/sidh_test.go
@@ -50,7 +50,7 @@ func TestStoreLoadDeleteSIDHPublicKey(t *testing.T) {
 		t.Errorf("Should not load deleted key: %+v", err)
 	}
 
-	// Now do the same for Type B keys
+	// Now do the same for Tag B keys
 
 	x2 := NewSIDHPublicKey(sidh.KeyVariantSidhB)
 	p2 := NewSIDHPrivateKey(sidh.KeyVariantSidhB)
@@ -114,7 +114,7 @@ func TestStoreLoadDeleteSIDHPrivateKey(t *testing.T) {
 		t.Errorf("Should not load deleted key: %+v", err)
 	}
 
-	// Now do the same for Type B keys
+	// Now do the same for Tag B keys
 
 	p2 := NewSIDHPrivateKey(sidh.KeyVariantSidhB)
 	p2.Generate(myRng)
diff --git a/switchboard/switchboard_test.go b/switchboard/switchboard_test.go
index 2a726c73cf55a5771db525ac8e86a75168abe596..59786de8b07ef377d6afb400ff09e36ee02b91bb 100644
--- a/switchboard/switchboard_test.go
+++ b/switchboard/switchboard_test.go
@@ -92,7 +92,7 @@ func TestSwitchboard_RegisterListener(t *testing.T) {
 	setType := sw.messageType.Get(mt)
 
 	if !setType.Has(l) {
-		t.Errorf("Listener is not registered by Message Type")
+		t.Errorf("Listener is not registered by Message Tag")
 	}
 
 }
@@ -159,7 +159,7 @@ func TestSwitchboard_RegisterFunc(t *testing.T) {
 	setType := sw.messageType.Get(mt)
 
 	if !setType.Has(lid.listener) {
-		t.Errorf("Listener is not registered by Message Type")
+		t.Errorf("Listener is not registered by Message Tag")
 	}
 
 	lid.listener.Hear(message.Receive{})
@@ -228,7 +228,7 @@ func TestSwitchboard_RegisterChan(t *testing.T) {
 	setType := sw.messageType.Get(mt)
 
 	if !setType.Has(lid.listener) {
-		t.Errorf("Listener is not registered by Message Type")
+		t.Errorf("Listener is not registered by Message Tag")
 	}
 
 	lid.listener.Hear(message.Receive{})
@@ -335,7 +335,7 @@ func TestSwitchboard_Unregister(t *testing.T) {
 	}
 
 	if setType.Has(lid1.listener) {
-		t.Errorf("Removed Listener not registered by Message Type, " +
+		t.Errorf("Removed Listener not registered by Message Tag, " +
 			"should not be")
 	}
 
@@ -345,6 +345,6 @@ func TestSwitchboard_Unregister(t *testing.T) {
 	}
 
 	if !setType.Has(lid2.listener) {
-		t.Errorf("Remaining Listener is not registered by Message Type")
+		t.Errorf("Remaining Listener is not registered by Message Tag")
 	}
 }