diff --git a/bindings/group.go b/bindings/group.go
index 787b17884aebc80038d379168f53fd442073517d..4bae7053464b4cec8683641c9940cc0b8c0717cd 100644
--- a/bindings/group.go
+++ b/bindings/group.go
@@ -22,57 +22,57 @@ import (
 )
 
 ////////////////////////////////////////////////////////////////////////////////
-// Group Chat Singleton Tracker                                               //
+// Group Singleton Tracker                                               //
 ////////////////////////////////////////////////////////////////////////////////
 
-// groupChatTrackerSingleton is used to track GroupChat objects so that they can be
+// groupTrackerSingleton is used to track Group objects so that they can be
 // referenced by ID back over the bindings.
-var groupChatTrackerSingleton = &groupChatTracker{
-	tracked: make(map[int]*GroupChat),
+var groupTrackerSingleton = &groupTracker{
+	tracked: make(map[int]*Group),
 	count:   0,
 }
 
-// groupChatTracker is a singleton used to keep track of extant GroupChat objects,
+// groupTracker is a singleton used to keep track of extant Group objects,
 // preventing race conditions created by passing it over the bindings.
-type groupChatTracker struct {
-	tracked map[int]*GroupChat
+type groupTracker struct {
+	tracked map[int]*Group
 	count   int
 	mux     sync.RWMutex
 }
 
-// make create a GroupChat from a groupChat.Wrapper, assigns it a unique ID, and
+// make create a Group from a groupStore.Group, assigns it a unique ID, and
 // adds it to the groupChatTracker.
-func (ut *groupChatTracker) make(gcInt gc.GroupChat) *GroupChat {
+func (ut *groupTracker) make(g gs.Group) *Group {
 	ut.mux.Lock()
 	defer ut.mux.Unlock()
 
 	id := ut.count
 	ut.count++
 
-	ut.tracked[id] = &GroupChat{
-		m:  gc.NewWrapper(gcInt),
+	ut.tracked[id] = &Group{
+		g:  g,
 		id: id,
 	}
 
 	return ut.tracked[id]
 }
 
-// get an GroupChat from the groupChatTracker given its ID.
-func (ut *groupChatTracker) get(id int) (*GroupChat, error) {
+// get a Group from the groupChatTracker given its ID.
+func (ut *groupTracker) get(id int) (*Group, error) {
 	ut.mux.RLock()
 	defer ut.mux.RUnlock()
 
-	c, exist := ut.tracked[id]
+	g, exist := ut.tracked[id]
 	if !exist {
 		return nil, errors.Errorf(
-			"Cannot get GroupChat for ID %d, does not exist", id)
+			"Cannot get Group for ID %d, does not exist", id)
 	}
 
-	return c, nil
+	return g, nil
 }
 
-// delete removes a GroupChat from the groupChatTracker.
-func (ut *groupChatTracker) delete(id int) {
+// delete removes a Group from the groupTracker.
+func (ut *groupTracker) delete(id int) {
 	ut.mux.Lock()
 	defer ut.mux.Unlock()
 
@@ -85,33 +85,17 @@ func (ut *groupChatTracker) delete(id int) {
 
 // GroupChat is a binding-layer group chat manager.
 type GroupChat struct {
-	m  *gc.Wrapper
-	id int
-}
-
-// GroupRequest is a bindings-layer interface that handles a group reception.
-//
-// Parameters:
-//  - payload - a byte serialized representation of a group.
-type GroupRequest interface {
-	Callback(payload Group)
+	m *gc.Wrapper
 }
 
-// LoadOrNewGroupChat creates a bindings-layer group chat manager.
+// NewGroupChat creates a bindings-layer group chat manager.
 //
 // Parameters:
 //  - e2eID - e2e object ID in the tracker.
-//  - groupID - GroupChat object ID in the tracker, given from previous call
-//    to LoadOrNewGroupChat.
 //  - requestFunc - a callback to handle group chat requests.
 //  - processor - the group chat message processor.
-func LoadOrNewGroupChat(e2eID, groupID int, requestFunc GroupRequest,
-	processor GroupChatProcessor) (*GroupChat, error) {
-	// Retrieve from singleton
-	groupChat, err := groupChatTrackerSingleton.get(groupID)
-	if err == nil { // If present, return group chat manager from singleton
-		return groupChat, nil
-	}
+func NewGroupChat(e2eID int,
+	requestFunc GroupRequest, processor GroupChatProcessor) (*GroupChat, error) {
 
 	// Get user from singleton
 	user, err := e2eTrackerSingleton.get(e2eID)
@@ -121,12 +105,8 @@ func LoadOrNewGroupChat(e2eID, groupID int, requestFunc GroupRequest,
 
 	// Construct a wrapper for the request callback
 	requestCb := func(g gs.Group) {
-		//fixme: review this to see if should be json marshaled.
-		// At the moment, groupStore.DhKeyList is an unsupported
-		// type, it would need a MarshalJson method. If we JSON marshal, change
-		// JoinGroup implementation and docstring accordingly.
-		// As for now, it's matching the construction as defined pre-restructure.
-		requestFunc.Callback(Group{g: g})
+		newGroup := groupTrackerSingleton.make(g)
+		requestFunc.Callback(newGroup)
 	}
 
 	// Construct a group chat manager
@@ -137,12 +117,8 @@ func LoadOrNewGroupChat(e2eID, groupID int, requestFunc GroupRequest,
 	}
 
 	// Construct wrapper
-	return groupChatTrackerSingleton.make(gcInt), nil
-}
-
-// GetID returns the groupChatTracker ID for the GroupChat object.
-func (g *GroupChat) GetID() int {
-	return g.id
+	wrapper := gc.NewWrapper(gcInt)
+	return &GroupChat{m: wrapper}, nil
 }
 
 // MakeGroup creates a new Group and sends a group request to all members in the
@@ -224,11 +200,26 @@ func (g *GroupChat) ResendRequest(groupId []byte) ([]byte, error) {
 }
 
 // JoinGroup allows a user to join a group when a request is received.
+// If an error is returned, handle it properly first; you may then retry later
+// with the same trackedGroupId.
 //
 // Parameters:
-//  - group - a bindings-level Group object. This is received by GroupRequest.Callback.
-func (g *GroupChat) JoinGroup(group Group) error {
-	return g.m.JoinGroup(group.g)
+//  - trackedGroupId - the ID to retrieve the Group object within the backend's
+//                     tracking system. This is received by GroupRequest.Callback.
+func (g *GroupChat) JoinGroup(trackedGroupId int) error {
+	// Retrieve group from singleton
+	grp, err := groupTrackerSingleton.get(trackedGroupId)
+	if err != nil {
+		return err
+	}
+
+	// Join group
+	err = g.m.JoinGroup(grp.g)
+	if err != nil {
+		return err
+	}
+
+	return nil
 }
 
 // LeaveGroup deletes a group so a user no longer has access.
@@ -292,22 +283,25 @@ func (g *GroupChat) GetGroups() ([]byte, error) {
 // error "failed to find group" is returned.
 //
 // Parameters:
-//  - groupId - the byte data representing a group ID.
-//    This can be pulled from a marshalled GroupReport.
+//  - groupId - The byte data representing a group ID (a byte marshalled id.ID).
+//              This can be pulled from a marshalled GroupReport.
 // Returns:
-//  - Group - the bindings-layer representation of a Group.
+//  - Group - The bindings-layer representation of a group.
 func (g *GroupChat) GetGroup(groupId []byte) (*Group, error) {
+	// Unmarshal group ID
 	groupID, err := id.Unmarshal(groupId)
 	if err != nil {
 		return nil, errors.Errorf("Failed to unmarshal group ID: %+v", err)
 	}
 
+	// Retrieve group from manager
 	grp, exists := g.m.GetGroup(groupID)
 	if !exists {
 		return nil, errors.New("failed to find group")
 	}
 
-	return &Group{g: grp}, nil
+	// Add to tracker and return Group object
+	return groupTrackerSingleton.make(grp), nil
 }
 
 // NumGroups returns the number of groups the user is a part of.
@@ -322,7 +316,8 @@ func (g *GroupChat) NumGroups() int {
 // Group structure contains the identifying and membership information of a
 // group chat.
 type Group struct {
-	g gs.Group
+	g  gs.Group
+	id int
 }
 
 // GetName returns the name set by the user for the group.
@@ -330,11 +325,16 @@ func (g *Group) GetName() []byte {
 	return g.g.Name
 }
 
-// GetID return the 33-byte unique group ID.
+// GetID return the 33-byte unique group ID. This represents the id.ID object
 func (g *Group) GetID() []byte {
 	return g.g.ID.Bytes()
 }
 
+// GetTrackedID returns the tracked ID of the Group object. This is used by the backend tracker.
+func (g *Group) GetTrackedID() int {
+	return g.id
+}
+
 // GetInitMessage returns initial message sent with the group request.
 func (g *Group) GetInitMessage() []byte {
 	return g.g.InitMessage
@@ -369,9 +369,17 @@ func (g *Group) Serialize() []byte {
 }
 
 //////////////////////////////////////////////////////////////////////////////////
-// Group Chat Processor
+// Callbacks
 //////////////////////////////////////////////////////////////////////////////////
 
+// GroupRequest is a bindings-layer interface that handles a group reception.
+//
+// Parameters:
+//  - trackedGroupId - a bindings layer Group object.
+type GroupRequest interface {
+	Callback(g *Group)
+}
+
 // GroupChatProcessor manages the handling of received group chat messages.
 type GroupChatProcessor interface {
 	Process(decryptedMessage, msg, receptionId []byte, ephemeralId,