diff --git a/channels/messages.pb.go b/channels/channelMessages.pb.go
similarity index 63%
rename from channels/messages.pb.go
rename to channels/channelMessages.pb.go
index 4f180c6029e6cdcea4376684797f19bf7913cf01..cd29a3cdfc0d0ad6369a963cafa1f76bd2b2130f 100644
--- a/channels/messages.pb.go
+++ b/channels/channelMessages.pb.go
@@ -9,7 +9,7 @@
 // versions:
 // 	protoc-gen-go v1.26.0
 // 	protoc        (unknown)
-// source: messages.proto
+// source: channelMessages.proto
 
 package channels
 
@@ -49,7 +49,7 @@ type ChannelMessage struct {
 func (x *ChannelMessage) Reset() {
 	*x = ChannelMessage{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_messages_proto_msgTypes[0]
+		mi := &file_channelMessages_proto_msgTypes[0]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -62,7 +62,7 @@ func (x *ChannelMessage) String() string {
 func (*ChannelMessage) ProtoMessage() {}
 
 func (x *ChannelMessage) ProtoReflect() protoreflect.Message {
-	mi := &file_messages_proto_msgTypes[0]
+	mi := &file_channelMessages_proto_msgTypes[0]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -75,7 +75,7 @@ func (x *ChannelMessage) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ChannelMessage.ProtoReflect.Descriptor instead.
 func (*ChannelMessage) Descriptor() ([]byte, []int) {
-	return file_messages_proto_rawDescGZIP(), []int{0}
+	return file_channelMessages_proto_rawDescGZIP(), []int{0}
 }
 
 func (x *ChannelMessage) GetLease() int64 {
@@ -139,7 +139,7 @@ type UserMessage struct {
 func (x *UserMessage) Reset() {
 	*x = UserMessage{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_messages_proto_msgTypes[1]
+		mi := &file_channelMessages_proto_msgTypes[1]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -152,7 +152,7 @@ func (x *UserMessage) String() string {
 func (*UserMessage) ProtoMessage() {}
 
 func (x *UserMessage) ProtoReflect() protoreflect.Message {
-	mi := &file_messages_proto_msgTypes[1]
+	mi := &file_channelMessages_proto_msgTypes[1]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -165,7 +165,7 @@ func (x *UserMessage) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use UserMessage.ProtoReflect.Descriptor instead.
 func (*UserMessage) Descriptor() ([]byte, []int) {
-	return file_messages_proto_rawDescGZIP(), []int{1}
+	return file_channelMessages_proto_rawDescGZIP(), []int{1}
 }
 
 func (x *UserMessage) GetMessage() []byte {
@@ -210,54 +210,55 @@ func (x *UserMessage) GetUsernameLease() int64 {
 	return 0
 }
 
-var File_messages_proto protoreflect.FileDescriptor
-
-var file_messages_proto_rawDesc = []byte{
-	0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x12, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x22, 0x7c, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x6e,
-	0x65, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x4c, 0x65, 0x61,
-	0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12,
-	0x18, 0x0a, 0x07, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
-	0x52, 0x07, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x50, 0x61, 0x79,
-	0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b,
-	0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x50,
-	0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61,
-	0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xdd, 0x01, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x65,
-	0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
-	0x30, 0x0a, 0x13, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x69, 0x67,
-	0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x76, 0x61,
-	0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72,
-	0x65, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03,
-	0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12,
-	0x1a, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x45,
-	0x43, 0x43, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28,
-	0x0c, 0x52, 0x0c, 0x65, 0x43, 0x43, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12,
-	0x24, 0x0a, 0x0d, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4c, 0x65, 0x61, 0x73, 0x65,
-	0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65,
-	0x4c, 0x65, 0x61, 0x73, 0x65, 0x42, 0x0b, 0x5a, 0x09, 0x2f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65,
-	0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+var File_channelMessages_proto protoreflect.FileDescriptor
+
+var file_channelMessages_proto_rawDesc = []byte{
+	0x0a, 0x15, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x22, 0x7c,
+	0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x12, 0x14, 0x0a, 0x05, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,
+	0x05, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x49,
+	0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x44,
+	0x12, 0x20, 0x0a, 0x0b, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79,
+	0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x04, 0x20,
+	0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xdd, 0x01, 0x0a,
+	0x0b, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07,
+	0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d,
+	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61,
+	0x74, 0x69, 0x6f, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x0c, 0x52, 0x13, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53,
+	0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e,
+	0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67,
+	0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61,
+	0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61,
+	0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x45, 0x43, 0x43, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
+	0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x65, 0x43, 0x43, 0x50, 0x75, 0x62,
+	0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0d, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61,
+	0x6d, 0x65, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x75,
+	0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x42, 0x0b, 0x5a, 0x09,
+	0x2f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x33,
 }
 
 var (
-	file_messages_proto_rawDescOnce sync.Once
-	file_messages_proto_rawDescData = file_messages_proto_rawDesc
+	file_channelMessages_proto_rawDescOnce sync.Once
+	file_channelMessages_proto_rawDescData = file_channelMessages_proto_rawDesc
 )
 
-func file_messages_proto_rawDescGZIP() []byte {
-	file_messages_proto_rawDescOnce.Do(func() {
-		file_messages_proto_rawDescData = protoimpl.X.CompressGZIP(file_messages_proto_rawDescData)
+func file_channelMessages_proto_rawDescGZIP() []byte {
+	file_channelMessages_proto_rawDescOnce.Do(func() {
+		file_channelMessages_proto_rawDescData = protoimpl.X.CompressGZIP(file_channelMessages_proto_rawDescData)
 	})
-	return file_messages_proto_rawDescData
+	return file_channelMessages_proto_rawDescData
 }
 
-var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
-var file_messages_proto_goTypes = []interface{}{
+var file_channelMessages_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_channelMessages_proto_goTypes = []interface{}{
 	(*ChannelMessage)(nil), // 0: parse.ChannelMessage
 	(*UserMessage)(nil),    // 1: parse.UserMessage
 }
-var file_messages_proto_depIdxs = []int32{
+var file_channelMessages_proto_depIdxs = []int32{
 	0, // [0:0] is the sub-list for method output_type
 	0, // [0:0] is the sub-list for method input_type
 	0, // [0:0] is the sub-list for extension type_name
@@ -265,13 +266,13 @@ var file_messages_proto_depIdxs = []int32{
 	0, // [0:0] is the sub-list for field type_name
 }
 
-func init() { file_messages_proto_init() }
-func file_messages_proto_init() {
-	if File_messages_proto != nil {
+func init() { file_channelMessages_proto_init() }
+func file_channelMessages_proto_init() {
+	if File_channelMessages_proto != nil {
 		return
 	}
 	if !protoimpl.UnsafeEnabled {
-		file_messages_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+		file_channelMessages_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*ChannelMessage); i {
 			case 0:
 				return &v.state
@@ -283,7 +284,7 @@ func file_messages_proto_init() {
 				return nil
 			}
 		}
-		file_messages_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+		file_channelMessages_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*UserMessage); i {
 			case 0:
 				return &v.state
@@ -300,18 +301,18 @@ func file_messages_proto_init() {
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_messages_proto_rawDesc,
+			RawDescriptor: file_channelMessages_proto_rawDesc,
 			NumEnums:      0,
 			NumMessages:   2,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
-		GoTypes:           file_messages_proto_goTypes,
-		DependencyIndexes: file_messages_proto_depIdxs,
-		MessageInfos:      file_messages_proto_msgTypes,
+		GoTypes:           file_channelMessages_proto_goTypes,
+		DependencyIndexes: file_channelMessages_proto_depIdxs,
+		MessageInfos:      file_channelMessages_proto_msgTypes,
 	}.Build()
-	File_messages_proto = out.File
-	file_messages_proto_rawDesc = nil
-	file_messages_proto_goTypes = nil
-	file_messages_proto_depIdxs = nil
+	File_channelMessages_proto = out.File
+	file_channelMessages_proto_rawDesc = nil
+	file_channelMessages_proto_goTypes = nil
+	file_channelMessages_proto_depIdxs = nil
 }
diff --git a/channels/messages.proto b/channels/channelMessages.proto
similarity index 100%
rename from channels/messages.proto
rename to channels/channelMessages.proto
diff --git a/channels/eventModel.go b/channels/eventModel.go
index 93841ba39764e6fe9e608070f1fda363c781e0dc..7b49b3bd544ef886736fb1104dd31340bc283e83 100644
--- a/channels/eventModel.go
+++ b/channels/eventModel.go
@@ -22,18 +22,37 @@ var (
 		"already been registered")
 )
 
+// EventModel is an interface which an external party which uses the channels
+// system passed an object which adheres to in order to get events on the channel
 type EventModel interface {
+	// JoinChannel is called whenever a channel is joined locally
 	JoinChannel(channel cryptoBroadcast.Channel)
+
+	// LeaveChannel is called whenever a channel is left locally
 	LeaveChannel(ChannelID *id.ID)
 
+	// ReceiveMessage is called whenever a message is received on a given channel
+	// It may be called multiple times on the same message, it is incumbent on
+	// the user of the API to filter such called by message ID
 	ReceiveMessage(ChannelID *id.ID, MessageID cryptoChannel.MessageID,
 		SenderUsername string, text string,
 		timestamp time.Time, lease time.Duration, round rounds.Round)
 
+	// ReceiveReply is called whenever a message is received which is a reply
+	// on a given channel. It may be called multiple times on the same message,
+	// it is incumbent on the user of the API to filter such called by message ID
+	// Messages may arrive our of order, so a reply in theory can arrive before
+	// the initial message, as a result it may be important to buffer replies.
 	ReceiveReply(ChannelID *id.ID, MessageID cryptoChannel.MessageID,
 		ReplyTo cryptoChannel.MessageID, SenderUsername string,
 		text string, timestamp time.Time, lease time.Duration,
 		round rounds.Round)
+
+	// ReceiveReaction is called whenever a reaction to a message is received
+	// on a given channel. It may be called multiple times on the same reaction,
+	// it is incumbent on the user of the API to filter such called by message ID
+	// Messages may arrive our of order, so a reply in theory can arrive before
+	// the initial message, as a result it may be important to buffer reactions.
 	ReceiveReaction(ChannelID *id.ID, MessageID cryptoChannel.MessageID,
 		ReactionTo cryptoChannel.MessageID, SenderUsername string,
 		Reaction string, timestamp time.Time, lease time.Duration,
@@ -57,6 +76,8 @@ type events struct {
 	mux        sync.RWMutex
 }
 
+// initEvents initializes the event model and registers default message type
+// handlers
 func initEvents(model EventModel) *events {
 	e := &events{
 		model:      model,
@@ -71,6 +92,11 @@ func initEvents(model EventModel) *events {
 	return e
 }
 
+// RegisterReceiveHandler is used to register handlers for non default message
+// types s they can be processed by modules. it is important that such modules
+// sync up with the event model implementation.
+// There can only be one handler per message type, and this will return an error
+// on a multiple registration.
 func (e *events) RegisterReceiveHandler(messageType MessageType,
 	listener MessageTypeReceiveMessage) error {
 	e.mux.Lock()
@@ -87,6 +113,9 @@ func (e *events) RegisterReceiveHandler(messageType MessageType,
 	return nil
 }
 
+// triggerEvent is an internal function which is used to trigger message
+// reception on a message received from a user (symmetric encryption)
+// It will call the appropriate MessageTypeHandler assuming one exists.
 func (e *events) triggerEvent(chID *id.ID, umi *UserMessageInternal,
 	receptionID receptionID.EphemeralIdentity, round rounds.Round) {
 	um := umi.GetUserMessage()
@@ -110,6 +139,9 @@ func (e *events) triggerEvent(chID *id.ID, umi *UserMessageInternal,
 	return
 }
 
+// triggerAdminEvent is an internal function which is used to trigger message
+// reception on a message received from the admin (asymmetric encryption)
+// It will call the appropriate MessageTypeHandler assuming one exists.
 func (e *events) triggerAdminEvent(chID *id.ID, cm *ChannelMessage,
 	messageID cryptoChannel.MessageID, receptionID receptionID.EphemeralIdentity, round rounds.Round) {
 	messageType := MessageType(cm.PayloadType)
@@ -131,6 +163,11 @@ func (e *events) triggerAdminEvent(chID *id.ID, cm *ChannelMessage,
 	return
 }
 
+// receiveTextMessage is the internal function which handles the reception of
+// text messages. It handles both messages and replies and calls the correct
+// function on the event model.
+// If the message has a reply but it is malformed, it will drop the reply and
+// write to the log
 func (e *events) receiveTextMessage(ChannelID *id.ID,
 	MessageID cryptoChannel.MessageID, messageType MessageType,
 	SenderUsername string, Content []byte, timestamp time.Time,
@@ -165,6 +202,9 @@ func (e *events) receiveTextMessage(ChannelID *id.ID,
 		timestamp, lease, round)
 }
 
+// receiveReaction is the internal function which handles the reception of
+// Reactions.
+// It does edge chaling
 func (e *events) receiveReaction(ChannelID *id.ID,
 	MessageID cryptoChannel.MessageID, messageType MessageType,
 	SenderUsername string, Content []byte, timestamp time.Time,
diff --git a/channels/generateProto.sh b/channels/generateProto.sh
index 13678dee233c7fd43c3f7977c7008d98096ccfed..3ab1d6b0536cf11fcfc898ad8ba57d977316d369 100755
--- a/channels/generateProto.sh
+++ b/channels/generateProto.sh
@@ -7,5 +7,5 @@
 #/ LICENSE file                                                               //
 #///////////////////////////////////////////////////////////////////////////////
 
-protoc --go_out=paths=source_relative:. messages.proto
+protoc --go_out=paths=source_relative:. channelMessages.proto
 protoc --go_out=paths=source_relative:. text.proto
diff --git a/channels/joinedChannel.go b/channels/joinedChannel.go
index 0496298d6136b771a1cd53b2342ef180bafb4e2f..c57c92e60cc497a082e0a0b529e118021948405a 100644
--- a/channels/joinedChannel.go
+++ b/channels/joinedChannel.go
@@ -68,7 +68,7 @@ func (m *manager) loadChannels() {
 
 	for i := range chList {
 		jc, err := loadJoinedChannel(chList[i], m.kv, m.client, m.rng, m.name,
-			&m.events, m.broadcastMaker)
+			m.events, m.broadcastMaker)
 		if err != nil {
 			jww.FATAL.Panicf("Failed to load channel %s:  %+v",
 				chList[i], err)
@@ -95,7 +95,7 @@ func (m *manager) addChannel(channel cryptoBroadcast.Channel) error {
 	//Connect to listeners
 	err = b.RegisterListener((&userListener{
 		name:   m.name,
-		events: &m.events,
+		events: m.events,
 		chID:   channel.ReceptionID,
 	}).Listen, broadcast.Symmetric)
 	if err != nil {
@@ -104,7 +104,7 @@ func (m *manager) addChannel(channel cryptoBroadcast.Channel) error {
 
 	err = b.RegisterListener((&adminListener{
 		name:   m.name,
-		events: &m.events,
+		events: m.events,
 		chID:   channel.ReceptionID,
 	}).Listen, broadcast.Asymmetric)
 	if err != nil {
diff --git a/channels/manager.go b/channels/manager.go
index ebad0194c14b4bece68862b8a26746e33620459e..51fb0bbc37af670133b4e791ba727d066117ceb6 100644
--- a/channels/manager.go
+++ b/channels/manager.go
@@ -21,15 +21,18 @@ type manager struct {
 	name   NameService
 
 	//Events model
-	events
+	*events
 
 	// make the function used to create broadcasts be a pointer so it
 	// can be replaced in tests
 	broadcastMaker broadcast.NewBroadcastChannelFunc
 }
 
+// NewManager Creates a new channel.Manager.
+// Prefix's teh KV with the username so multiple instances for multiple
+// users will not error.
 func NewManager(kv *versioned.KV, client broadcast.Client,
-	rng *fastRNG.StreamGenerator, name NameService) Manager {
+	rng *fastRNG.StreamGenerator, name NameService, model EventModel) Manager {
 
 	//prefix the kv with the username so multiple can be run
 	kv = kv.Prefix(name.GetUsername())
@@ -39,15 +42,18 @@ func NewManager(kv *versioned.KV, client broadcast.Client,
 		client:         client,
 		rng:            rng,
 		name:           name,
-		events:         events{},
 		broadcastMaker: broadcast.NewBroadcastChannel,
 	}
 
+	m.events = initEvents(model)
+
 	m.loadChannels()
 
 	return &m
 }
 
+// JoinChannel joins the given channel. Will fail if the channel
+// has already been joined.
 func (m *manager) JoinChannel(channel cryptoBroadcast.Channel) error {
 	err := m.addChannel(channel)
 	if err != nil {
@@ -57,6 +63,8 @@ func (m *manager) JoinChannel(channel cryptoBroadcast.Channel) error {
 	return nil
 }
 
+// LeaveChannel leaves the given channel. It will return an error
+// if the channel was not previously joined.
 func (m *manager) LeaveChannel(channelId *id.ID) error {
 	err := m.removeChannel(channelId)
 	if err != nil {
diff --git a/channels/send.go b/channels/send.go
index 86b34441aabd3e6a3d9a657cad2a177ae542b07d..636fe66332c5b2ebc2341ef7f277e813b7c7f84a 100644
--- a/channels/send.go
+++ b/channels/send.go
@@ -16,6 +16,12 @@ const (
 	cmixChannelReactionVersion = 0
 )
 
+// SendGeneric is used to send a raw message over a channel. In general, it
+// should be wrapped in a function which defines the wire protocol
+// If the final message, before being sent over the wire, is too long, this will
+// return an error. Due to the underlying encoding using compression, it isn't
+// possible to define the largest payload that can be sent, but
+// it will always be possible to send a payload of 802 bytes at minimum
 func (m *manager) SendGeneric(channelID *id.ID, messageType MessageType,
 	msg []byte, validUntil time.Duration, params cmix.CMIXParams) (
 	cryptoChannel.MessageID, id.Round, ephemeral.Id, error) {
@@ -62,7 +68,7 @@ func (m *manager) SendGeneric(channelID *id.ID, messageType MessageType,
 			Signature:           messageSig,
 			Username:            m.name.GetUsername(),
 			ECCPublicKey:        m.name.GetChannelPubkey(),
-			UsernameLease:       unameLease.Unix(),
+			UsernameLease:       unameLease.UnixNano(),
 		}
 
 		//Serialize the user message
@@ -89,6 +95,11 @@ func (m *manager) SendGeneric(channelID *id.ID, messageType MessageType,
 	return msgId, rid, ephid, err
 }
 
+// SendAdminGeneric is used to send a raw message over a channel encrypted
+// with admin keys, identifying it as sent by the admin. In general, it
+// should be wrapped in a function which defines the wire protocol
+// If the final message, before being sent over the wire, is too long, this will
+// return an error. The message must be at most 510 bytes long.
 func (m *manager) SendAdminGeneric(privKey *rsa.PrivateKey, channelID *id.ID,
 	msg []byte, validUntil time.Duration, messageType MessageType,
 	params cmix.CMIXParams) (cryptoChannel.MessageID, id.Round, ephemeral.Id,
@@ -145,6 +156,10 @@ func (m *manager) SendAdminGeneric(privKey *rsa.PrivateKey, channelID *id.ID,
 	return msgId, rid, ephid, err
 }
 
+// SendMessage is used to send a formatted message over a channel.
+// Due to the underlying encoding using compression, it isn't
+// possible to define the largest payload that can be sent, but
+// it will always be possible to send a payload of 798 bytes at minimum
 func (m *manager) SendMessage(channelID *id.ID, msg string,
 	validUntil time.Duration, params cmix.CMIXParams) (
 	cryptoChannel.MessageID, id.Round, ephemeral.Id, error) {
@@ -162,6 +177,12 @@ func (m *manager) SendMessage(channelID *id.ID, msg string,
 	return m.SendGeneric(channelID, Text, txtMarshaled, validUntil, params)
 }
 
+// SendReply is used to send a formatted message over a channel.
+// Due to the underlying encoding using compression, it isn't
+// possible to define the largest payload that can be sent, but
+// it will always be possible to send a payload of 766 bytes at minimum.
+// If the message ID the reply is sent to doesnt exist, the other side will
+// post the message as a normal message and not a reply.
 func (m *manager) SendReply(channelID *id.ID, msg string,
 	replyTo cryptoChannel.MessageID, validUntil time.Duration,
 	params cmix.CMIXParams) (cryptoChannel.MessageID, id.Round, ephemeral.Id,
@@ -180,8 +201,12 @@ func (m *manager) SendReply(channelID *id.ID, msg string,
 	return m.SendGeneric(channelID, Text, txtMarshaled, validUntil, params)
 }
 
+// SendReaction is used to send a reaction to a message over a channel.
+// The reaction must be a single emoji with no other characters, and will
+// be rejected otherwise.
+// Clients will drop the reaction if they do not recognize the reactTo message
 func (m *manager) SendReaction(channelID *id.ID, reaction string,
-	replyTo cryptoChannel.MessageID, validUntil time.Duration,
+	reactTo cryptoChannel.MessageID, validUntil time.Duration,
 	params cmix.CMIXParams) (cryptoChannel.MessageID, id.Round, ephemeral.Id,
 	error) {
 
@@ -192,7 +217,7 @@ func (m *manager) SendReaction(channelID *id.ID, reaction string,
 	react := &CMIXChannelReaction{
 		Version:           cmixChannelReactionVersion,
 		Reaction:          reaction,
-		ReactionMessageID: replyTo[:],
+		ReactionMessageID: reactTo[:],
 	}
 
 	reactMarshaled, err := proto.Marshal(react)