diff --git a/bindings/e2eHandler.go b/bindings/e2eHandler.go
index bfd439c133b468c4b0296ec09ae67b7f9045c169..8366299d37676a2d8f43878c66b7eedc8e347cfd 100644
--- a/bindings/e2eHandler.go
+++ b/bindings/e2eHandler.go
@@ -10,7 +10,8 @@ package bindings
 import (
 	"encoding/json"
 	"fmt"
-
+	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/catalog"
 	"gitlab.com/elixxir/client/cmix/identity/receptionID"
 	"gitlab.com/elixxir/client/cmix/rounds"
@@ -157,6 +158,42 @@ func (e *E2e) AddService(tag string, processor Processor) error {
 		tag, &messageProcessor{bindingsCbs: processor})
 }
 
+// RegisterListener registers a new listener.
+//
+// Parameters:
+//  - senderId - the user ID who sends messages to this user that
+//    this function will register a listener for.
+//  - messageType - message type from the sender you want to listen for.
+//  - newListener: A provider for a callback to hear a message.
+//    Do not pass nil to this.
+func (e *E2e) RegisterListener(senderID []byte,
+	messageType int,
+	newListener Listener) error {
+	jww.INFO.Printf("RegisterListener(%v, %d)", senderID,
+		messageType)
+
+	// Convert senderID to id.Id object
+	var uid *id.ID
+	if len(senderID) == 0 {
+		uid = &id.ID{}
+	} else {
+		var err error
+		uid, err = id.Unmarshal(senderID)
+		if err != nil {
+			return errors.New(fmt.Sprintf("Failed to "+
+				"ResgisterListener: %+v", err))
+		}
+	}
+
+	// Register listener
+	// todo: when implementing an unregister function, return and provide a way
+	//  track this listener ID
+	_ = e.api.GetE2E().RegisterListener(uid,
+		catalog.MessageType(messageType), listener{l: newListener})
+
+	return nil
+}
+
 // Processor is the bindings-specific interface for message.Processor methods.
 type Processor interface {
 	Process(message []byte, receptionId []byte, ephemeralId int64, roundId int64)
diff --git a/bindings/errors.go b/bindings/errors.go
new file mode 100644
index 0000000000000000000000000000000000000000..32c945c80c219626623b39ce12e3f299c1f73cef
--- /dev/null
+++ b/bindings/errors.go
@@ -0,0 +1,121 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package bindings
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"github.com/pkg/errors"
+	"strings"
+	"sync"
+)
+
+// errToUserErr maps backend patterns to user-friendly error messages.
+// Example format:
+// (Back-end) "Building new HostPool because no HostList stored:":  (Front-end) "Missing host list",
+var errToUserErr = map[string]string{
+	// Registration errors
+	//"cannot create username when network is not health" :
+	//	"Cannot create username, unable to connect to network",
+	//"failed to add due to malformed fact stringified facts must at least have a type at the start" :
+	//	"Invalid fact, is the field empty?",
+	//// UD failures
+	//"failed to create user discovery manager: cannot return single manager, network is not health" :
+	//	"Could not connect to user discovery",
+	//"user discovery returned error on search: no results found" :
+	//	"No results found",
+	//"failed to search.: waiting for response to single-use transmisson timed out after 10s" :
+	//	"Search timed out",
+	//"the phone number supplied was empty" : "Invalid phone number",
+	//"failed to create user discovery manager: cannot start ud manager when network follower is not running." :
+	//	"Could not get network status",
+}
+
+// error<Mux is a global lock for the errToUserErr global.
+var errorMux sync.RWMutex
+
+// Error codes
+const (
+	UnrecognizedCode    = "UR: "
+	UnrecognizedMessage = UnrecognizedCode + "Unrecognized error from XX backend, please report"
+)
+
+// CreateUserFriendlyErrorMessage will convert the passed in error string
+// to an error string that is user-friendly if a substring match is
+// found to a common error. Common errors is a map which can be updated
+// using UpdateCommonErrors. If the error is not common, some simple parsing
+// is done on the error message to make it more user-accessible, removing
+// backend specific jargon.
+//
+// Parameters
+//   - errStr - an error returned from the backend.
+//
+// Returns
+//  - A user-friendly error message. This should be devoid of technical speak
+//    but still be meaningful for front-end or back-end teams.
+func CreateUserFriendlyErrorMessage(errStr string) string {
+	errorMux.RLock()
+	defer errorMux.RUnlock()
+	// Go through common errors
+	for backendErr, userFriendly := range errToUserErr {
+		// Determine if error contains a common error
+		if strings.Contains(errStr, backendErr) {
+			return userFriendly
+		}
+	}
+
+	descStr := "desc = "
+	// If this contains an rpc error, determine how to handle it
+	if strings.Contains(errStr, context.DeadlineExceeded.Error()) {
+		// If there is a context deadline exceeded message, return the higher level
+		// as context deadline exceeded is not informative
+		rpcErr := "rpc "
+		rpcIdx := strings.Index(errStr, rpcErr)
+		return errStr[:rpcIdx]
+	} else if strings.Contains(errStr, descStr) {
+		// If containing an rpc error where context deadline exceeded
+		// is NOT involved, the error returned server-side is often
+		//more informative
+		descIdx := strings.Index(errStr, descStr)
+		// return everything after "desc = "
+		return errStr[descIdx+len(descStr):]
+	}
+
+	// If a compound error message, return the highest level message
+	errParts := strings.Split(errStr, ":")
+	if len(errParts) > 1 {
+		// Return everything before the first :
+		return UnrecognizedCode + errParts[0]
+	}
+
+	return fmt.Sprintf("%s: %v", UnrecognizedCode, errStr)
+}
+
+// UpdateCommonErrors updates the internal error mapping DB. This internal database
+// maps errors returned from the backend to user-friendly error messages.
+//
+// Parameters
+//  - jsonFile - contents of a JSON file whose format conforms to the example below.
+// Example Input:
+//   {
+//  	"Failed to Unmarshal Conversation": "Could not retrieve conversation",
+//  	"Failed to unmarshal SentRequestMap": "Failed to pull up friend requests",
+//  	"cannot create username when network is not health": "Cannot create username, unable to connect to network",
+//  }
+func UpdateCommonErrors(jsonFile string) error {
+	errorMux.Lock()
+	defer errorMux.Unlock()
+	err := json.Unmarshal([]byte(jsonFile), &errToUserErr)
+	if err != nil {
+		return errors.WithMessage(err, "Failed to unmarshal json file, "+
+			"did you pass in the contents or the path?")
+	}
+
+	return nil
+}
diff --git a/bindings/errors_test.go b/bindings/errors_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..0dbcf0220e1232aa450d0884363e4c461fe42c66
--- /dev/null
+++ b/bindings/errors_test.go
@@ -0,0 +1,107 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package bindings
+
+import (
+	"context"
+	"strings"
+	"testing"
+)
+
+// Unit test
+func TestErrorStringToUserFriendlyMessage(t *testing.T) {
+	// Setup: Populate map
+	backendErrs := []string{"Failed to Unmarshal Conversation", "failed to create group key preimage",
+		"Failed to unmarshal SentRequestMap"}
+	userErrs := []string{"Could not retrieve conversation", "Failed to initiate group chat",
+		"Failed to pull up friend requests"}
+
+	for i, exampleErr := range backendErrs {
+		errToUserErr[exampleErr] = userErrs[i]
+	}
+
+	// Check if a mapped common error returns the expected user-friendly error
+	received := CreateUserFriendlyErrorMessage(backendErrs[0])
+	if strings.Compare(received, userErrs[0]) != 0 {
+		t.Errorf("Unexpected user friendly message returned from common error mapping."+
+			"\n\tExpected: %s"+
+			"\n\tReceived: %v", userErrs[0], received)
+	}
+
+	// Test RPC error in which high level information should
+	// be passed along (ie context deadline exceeded error)
+	expected := "Could not poll network: "
+	rpcPrefix := "rpc error: desc = "
+	rpcErr := expected + rpcPrefix + context.DeadlineExceeded.Error()
+	received = CreateUserFriendlyErrorMessage(rpcErr)
+	if strings.Compare(expected, received) != 0 {
+		t.Errorf("Rpc error parsed unxecpectedly with error "+
+			"\n\"%s\" "+
+			"\n\tExpected: %s"+
+			"\n\tReceived: %v", rpcErr, UnrecognizedCode+expected, received)
+	}
+
+	// Test RPC error where server side error information is provided
+	serverSideError := "Could not parse message! Please try again with a properly crafted message"
+	rpcErr = rpcPrefix + serverSideError
+	received = CreateUserFriendlyErrorMessage(rpcErr)
+	if strings.Compare(serverSideError, received) != 0 {
+		t.Errorf("RPC error parsed unexpectedly with error "+
+			"\n\"%s\" "+
+			"\n\tExpected: %s"+
+			"\n\tReceived: %v", rpcErr, UnrecognizedCode+serverSideError, received)
+	}
+
+	// Test uncommon error, should return highest level message
+	expected = "failed to register with permissioning"
+	uncommonErr := expected + ": sendRegistrationMessage: Unable to contact Identity Server"
+	received = CreateUserFriendlyErrorMessage(uncommonErr)
+	if strings.Compare(received, UnrecognizedCode+expected) != 0 {
+		t.Errorf("Uncommon error parsed unexpectedly with error "+
+			"\n\"%s\" "+
+			"\n\tExpected: %s"+
+			"\n\tReceived: %s", uncommonErr, UnrecognizedCode+expected, received)
+	}
+
+	// Test fully unrecognizable and un-parsable message,
+	// should hardcoded error message
+	uncommonErr = "failed to register with permissioning"
+	received = CreateUserFriendlyErrorMessage(uncommonErr)
+	if strings.Compare(UnrecognizedCode+": "+uncommonErr, received) != 0 {
+		t.Errorf("Uncommon error parsed unexpectedly with error "+
+			"\n\"%s\" "+
+			"\n\tExpected: %s"+
+			"\n\tReceived: %s", uncommonErr, UnrecognizedMessage, received)
+	}
+
+}
+
+// Unit test
+func TestClient_UpdateCommonErrors(t *testing.T) {
+
+	key, expectedVal := "failed to create group key preimage", "Failed to initiate group chat"
+
+	jsonData := "{\"Failed to Unmarshal Conversation\":\"Could not retrieve conversation\",\"Failed to unmarshal SentRequestMap\":\"Failed to pull up friend requests\",\"failed to create group key preimage\":\"Failed to initiate group chat\"}\n"
+
+	err := UpdateCommonErrors(jsonData)
+	if err != nil {
+		t.Fatalf("UpdateCommonErrors error: %v", err)
+	}
+
+	val, ok := errToUserErr[key]
+	if !ok {
+		t.Fatalf("Expected entry was not populated")
+	}
+
+	if strings.Compare(expectedVal, val) != 0 {
+		t.Fatalf("Entry in updated error map was not expected."+
+			"\n\tExpected: %s"+
+			"\n\tReceived: %s", expectedVal, val)
+	}
+
+}
diff --git a/bindings/identity.go b/bindings/identity.go
index bda224053da1dc8c557f48cfb6a577be9e00b8cd..4af1ee4275cf5db0e469c9ed87b07a2a6ea39277 100644
--- a/bindings/identity.go
+++ b/bindings/identity.go
@@ -89,6 +89,12 @@ func (c *Cmix) MakeLegacyReceptionIdentity() ([]byte, error) {
 	return ident.Marshal()
 }
 
+// GetReceptionRegistrationValidationSignature returns the signature provided by
+// the xx network.
+func (c *Cmix) GetReceptionRegistrationValidationSignature() []byte {
+	return c.api.GetStorage().GetReceptionRegistrationValidationSignature()
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Contact Functions                                                          //
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/bindings/ud.go b/bindings/ud.go
index 611d94f49c833f76a6f44f8a43f4f809610470ca..413aabf6d9e029c9472dbf5dd002f5d9b943b364 100644
--- a/bindings/ud.go
+++ b/bindings/ud.go
@@ -110,6 +110,10 @@ type UdNetworkStatus interface {
 // Parameters:
 //  - e2eID - e2e object ID in the tracker
 //  - follower - network follower func wrapped in UdNetworkStatus
+//  - username - the username the user wants to register with UD.
+//    If the user is already registered, this field may be blank
+//  - registrationValidationSignature - the signature provided by the xx network.
+//    This signature is optional for other consumers who deploy their own UD.
 func LoadOrNewUserDiscovery(e2eID int, follower UdNetworkStatus,
 	username string, registrationValidationSignature []byte) (
 	*UserDiscovery, error) {