diff --git a/bindings/contact.go b/bindings/contact.go
index cfebb078270de5a36baa7f341e4cbbfdfb5d39a9..1cdef91938445b1e401b0be58d6e6d32de315115 100644
--- a/bindings/contact.go
+++ b/bindings/contact.go
@@ -8,12 +8,27 @@
 package bindings
 
 import (
-	"errors"
 	"gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/primitives/fact"
 )
 
 /* fact object*/
+//creates a new fact. The factType must be either:
+//  0 - Username
+//  1 - Email
+//  2 - Phone Number
+// The fact must be well formed for the type and must not include commas or
+// semicolons. If it is not well formed, it will be rejected.  Phone numbers
+// must have the two letter country codes appended.  For the complete set of
+// validation, see /elixxir/primitives/fact/fact.go
+func NewFact(factType int, factStr string)(*Fact, error){
+	f, err := fact.NewFact(fact.FactType(factType), factStr)
+	if err!=nil{
+		return nil, err
+	}
+	return &Fact{f:&f}, nil
+}
+
 type Fact struct {
 	f *fact.Fact
 }
@@ -26,6 +41,10 @@ func (f *Fact) Type() int {
 	return int(f.f.T)
 }
 
+func (f *Fact) Stringify() string {
+	return f.f.Stringify()
+}
+
 /* contact object*/
 type Contact struct {
 	c *contact.Contact
@@ -54,32 +73,3 @@ func (c *Contact) GetFactList() *FactList {
 func (c *Contact) Marshal() ([]byte, error) {
 	return c.c.Marshal()
 }
-
-/* FactList object*/
-type FactList struct {
-	c *contact.Contact
-}
-
-func (fl *FactList) Num() int {
-	return len(fl.c.Facts)
-}
-
-func (fl *FactList) Get(i int) Fact {
-	return Fact{f: &(fl.c.Facts)[i]}
-}
-
-func (fl *FactList) Add(factData string, factType int) error {
-	ft := fact.FactType(factType)
-	if !ft.IsValid() {
-		return errors.New("Invalid fact type")
-	}
-	fl.c.Facts = append(fl.c.Facts, fact.Fact{
-		Fact: factData,
-		T:    ft,
-	})
-	return nil
-}
-
-func (fl *FactList) Marshal() ([]byte, error) {
-	return []byte(fl.c.Facts.Stringify()), nil
-}
diff --git a/bindings/interfaces.go b/bindings/interfaces.go
deleted file mode 100644
index f827aefb50265cbec7b9f7463e86f737febd0394..0000000000000000000000000000000000000000
--- a/bindings/interfaces.go
+++ /dev/null
@@ -1,202 +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 bindings
-
-/*
-// Client is defined inside the api package. At minimum, it implements all of
-// functionality defined here. A Client handles all network connectivity, key
-// generation, and storage for a given cryptographic identity on the cmix
-// network.
-// These threads may become a significant drain on battery when offline, ensure
-// they are stopped if there is no internet access
-type client interface {
-	// ----- Network -----
-	// StartNetworkFollower kicks off the tracking of the network. It starts
-	// long running network client threads and returns an object for checking
-	// state and stopping those threads.
-	// Call this when returning from sleep and close when going back to
-	// sleep.
-	StartNetworkFollower() error
-
-	// StopNetworkFollower stops the network follower if it is running.
-	// It returns errors if the Follower is in the wrong status to stop or if it
-	// fails to stop it.
-	// if the network follower is running and this fails, the client object will
-	// most likely be in an unrecoverable state and need to be trashed.
-	StopNetworkFollower(timeoutMS int) error
-
-	// NetworkFollowerStatus gets the state of the network follower.
-	// Returns:
-	// 	Stopped 	- 0
-	// 	Starting	- 1000
-	// 	Running		- 2000
-	// 	Stopping	- 3000
-	NetworkFollowerStatus() int
-
-	// Returns true if the following of the network is in a state where messages
-	// can be sent, false otherwise
-	IsNetworkHealthy() bool
-
-	// Registers a callback which gets triggered every time network health
-	// changes
-	RegisterNetworkHealthCB(func(bool))
-
-	// ----- Reception -----
-
-	// RegisterListener records and installs a listener for messages
-	// matching specific uid, msgType, and/or username
-	RegisterListener(uid []byte, msgType int, username string,
-		listener Listener)
-
-	// ----- Transmission -----
-
-	// SendE2E sends an end-to-end payload to the provided recipient with
-	// the provided msgType. Returns the list of rounds in which parts of
-	// the message were sent or an error if it fails.
-	SendE2E(payload, recipient []byte, msgType int) (RoundList, error)
-	// SendUnsafe sends an unencrypted payload to the provided recipient
-	// with the provided msgType. Returns the list of rounds in which parts
-	// of the message were sent or an error if it fails.
-	// NOTE: Do not use this function unless you know what you are doing.
-	// This function always produces an error message in client logging.
-	SendUnsafe(payload, recipient []byte, msgType int) (RoundList, error)
-	// SendCMIX sends a "raw" CMIX message payload to the provided
-	// recipient. Note that both SendE2E and SendUnsafe call SendCMIX.
-	// Returns the round ID of the round the payload was sent or an error
-	// if it fails.
-	SendCMIX(payload, recipient []byte) (int, error)
-
-	// ----- Notifications -----
-
-	// RegisterForNotifications allows a client to register for push
-	// notifications.
-	// Note that clients are not required to register for push notifications
-	// especially as these rely on third parties (i.e., Firebase *cough*
-	// *cough* google's palantir *cough*) that may represent a security
-	// risk to the user.
-	RegisterForNotifications(token []byte) error
-	// UnregisterForNotifications turns of notifications for this client
-	UnregisterForNotifications() error
-
-	// ----- Registration -----
-
-	// Returns true if the cryptographic identity has been registered with
-	// the CMIX user discovery agent.
-	// Note that clients do not need to perform this step if they use
-	// out of band methods to exchange cryptographic identities
-	// (e.g., QR codes), but failing to be registered precludes usage
-	// of the user discovery mechanism (this may be preferred by user).
-	IsRegistered() bool
-
-	// RegisterIdentity registers an arbitrary username with the user
-	// discovery protocol. Returns an error when it cannot connect or
-	// the username is already registered.
-	RegisterIdentity(username string) error
-	// RegisterEmail makes the users email searchable after confirmation.
-	// It returns a registration confirmation token to be used with
-	// ConfirmRegistration or an error on failure.
-	RegisterEmail(email string) ([]byte, error)
-	// RegisterPhone makes the users phone searchable after confirmation.
-	// It returns a registration confirmation token to be used with
-	// ConfirmRegistration or an error on failure.
-	RegisterPhone(phone string) ([]byte, error)
-	// ConfirmRegistration sends the user discovery agent a confirmation
-	// token (from Register Email/Phone) and code (string sent via Email
-	// or SMS to confirm ownership) to confirm ownership.
-	ConfirmRegistration(token, code []byte) error
-
-	// ----- Contacts -----
-
-	// GetUser returns the current user Identity for this client. This
-	// can be serialized into a byte stream for out-of-band sharing.
-	GetUser() (bind.Contact, error)
-
-	// ----- User Discovery -----
-
-	// Search accepts a "separator" separated list of search elements with
-	// an associated list of searchTypes. It returns a ContactList which
-	// allows you to iterate over the found contact objects.
-	Search(data, separator string, searchTypes []byte) ContactList
-	// SearchWithHandler is a non-blocking search that also registers
-	// a callback interface for user disovery events.
-	SearchWithHandler(data, separator string, searchTypes []byte,
-		hdlr UserDiscoveryHandler)
-
-	// ----- Key Exchange -----
-
-	// CreateAuthenticatedChannel creates a 1-way authenticated channel
-	// so this user can send messages to the desired recipient Contact.
-	// To receive confirmation from the remote user, clients must
-	// register a listener to do that.
-	CreateAuthenticatedChannel(recipient bind.Contact, payload []byte) error
-	// RegierAuthEventsHandler registers a callback interface for channel
-	// authentication events.
-	RegisterAuthEventsHandler(hdlr AuthEventHandler)
-
-	// ----- Network -----
-
-	// RegisterRoundEventsHandler registers a callback interface for round
-	// events.
-	RegisterRoundEventsHandler()
-}
-
-// ContactList contains a list of contacts
-type ContactList interface {
-	// GetLen returns the number of contacts in the list
-	GetLen() int
-	// GetContact returns the contact at index i
-	GetContact(i int) bind.Contact
-}
-
-// ----- Callback interfaces -----
-
-
-
-// AuthEventHandler handles authentication requests initiated by
-// CreateAuthenticatedChannel
-type AuthEventHandler interface {
-	// HandleConfirmation handles AuthEvents received after
-	// the client has called CreateAuthenticatedChannel for
-	// the provided contact. Payload is typically empty but
-	// may include a small introductory message.
-	HandleConfirmation(contact bind.Contact, payload []byte)
-	// HandleRequest handles AuthEvents received before
-	// the client has called CreateAuthenticatedChannel for
-	// the provided contact. It should prompt the user to accept
-	// the channel creation "request" and, if approved,
-	// call CreateAuthenticatedChannel for this Contact.
-	HandleRequest(contact bind.Contact, payload []byte)
-}
-
-// UserDiscoveryHandler handles search results against the user discovery agent.
-type UserDiscoveryHandler interface {
-	HandleSearchResults(results ContactList)
-}
-
-
-// Message is a message received from the cMix network in the clear
-// or that has been decrypted using established E2E keys.
-type Message interface {
-	//Returns the id of the message
-	GetID() []byte
-
-	// Returns the message's sender ID, if available
-	GetSender() []byte
-
-	// Returns the message payload/contents
-	// Parse this with protobuf/whatever according to the message type
-	GetPayload() []byte
-
-	// Returns the message's type
-	GetMessageType() int
-
-	// Returns the message's timestamp in milliseconds since unix epoc
-	GetTimestampMS() int
-	// Returns the message's timestamp in ns since unix epoc
-	GetTimestampNano() int
-}*/
diff --git a/bindings/list.go b/bindings/list.go
index 5657bcb456706c28905a9c58f33e891eae61fba3..fda887f93f12860d90792405a6ef0e3864f3a30c 100644
--- a/bindings/list.go
+++ b/bindings/list.go
@@ -9,9 +9,13 @@ package bindings
 
 import (
 	"errors"
+	"gitlab.com/elixxir/client/interfaces/contact"
+	"gitlab.com/elixxir/primitives/fact"
 	"gitlab.com/xx_network/primitives/id"
 )
 
+/*IntList*/
+
 type IntList struct {
 	lst []int
 }
@@ -35,6 +39,8 @@ func (il *IntList) Get(i int) (int, error) {
 	return il.lst[i], nil
 }
 
+/*RoundList*/
+
 type RoundList struct {
 	list []id.Round
 }
@@ -53,3 +59,59 @@ func (rl *RoundList) Get(i int) (int, error) {
 
 	return int(rl.list[i]), nil
 }
+
+/*ContactList*/
+
+type ContactList struct {
+	list []contact.Contact
+}
+
+// Gets the number of round IDs stored
+func (cl *ContactList) Len() int {
+	return len(cl.list)
+}
+
+// Gets a stored round ID at the given index
+func (cl *ContactList) Get(i int) (*Contact, error) {
+	if i < 0 || i > len(cl.list) {
+		return nil, errors.New("contact cannot be under 0 or over" +
+			" list len")
+	}
+
+	return &Contact{c:&cl.list[i]}, nil
+}
+
+/*FactList*/
+func NewFactList()*FactList{
+	return &FactList{ c: &contact.Contact{
+		ID:             nil,
+		DhPubKey:       nil,
+		OwnershipProof: nil,
+		Facts:          make([]fact.Fact,0),
+	}}
+}
+
+type FactList struct {
+	c *contact.Contact
+}
+
+func (fl *FactList) Num() int {
+	return len(fl.c.Facts)
+}
+
+func (fl *FactList) Get(i int) Fact {
+	return Fact{f: &(fl.c.Facts)[i]}
+}
+
+func (fl *FactList) Add(factData string, factType int) error {
+	f, err := fact.NewFact(fact.FactType(factType), factData)
+	if err!=nil{
+		return err
+	}
+	fl.c.Facts = append(fl.c.Facts, f)
+	return nil
+}
+
+func (fl *FactList) Stringify() (string, error) {
+	return fl.c.Facts.Stringify(), nil
+}
diff --git a/bindings/ud.go b/bindings/ud.go
new file mode 100644
index 0000000000000000000000000000000000000000..bae84a46f6b040a7a366cd51396f0c433278da0a
--- /dev/null
+++ b/bindings/ud.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 bindings
+
+import (
+	"github.com/pkg/errors"
+	"gitlab.com/elixxir/client/interfaces/contact"
+	"gitlab.com/elixxir/client/ud"
+	"gitlab.com/elixxir/primitives/fact"
+	"gitlab.com/xx_network/primitives/id"
+	"time"
+)
+
+//This package wraps the user discovery system
+
+// User Discovery object
+type UserDiscovery struct{
+	ud *ud.Manager
+}
+
+// Returns a new user discovery object. Only call this once. It must be called
+// after StartNetworkFollower is called and will fail if the network has never
+// been contacted.
+// This function technically has a memory leak because it causes both sides of
+// the bindings to think the other is in charge of the client object.
+// In general this is not an issue because the client object should exist
+// for the life of the program.
+func NewUserDiscovery(client *Client)(*UserDiscovery, error){
+	m, err := ud.NewManager(&client.api)
+
+	if err!=nil{
+		return nil, err
+	}else{
+		return &UserDiscovery{ud:m}, nil
+	}
+}
+
+// Register registers a user with user discovery. Will return an error if the
+// network signatures are malformed or if the username is taken. Usernames
+// cannot be changed after registration at this time. Will fail if the user is
+// already registered.
+// Registration does not go over cmix, it occurs over normal communications
+func (ud *UserDiscovery)Register(username string)error{
+	return ud.ud.Register(username)
+}
+
+// Adds a fact for the user to user discovery. Will only succeed if the
+// user is already registered and the system does not have the fact currently
+// registered for any user.
+// Will fail if the fact string is not well formed.
+// This does not complete the fact registration process, it returns a
+// confirmation id instead. Over the communications system the fact is
+// associated with, a code will be sent. This confirmation ID needs to be
+// called along with the code to finalize the fact.
+func (ud *UserDiscovery)AddFact(fStr string)(string, error){
+	f, err := fact.UnstringifyFact(fStr)
+	if err !=nil{
+		return "", errors.WithMessage(err, "Failed to add due to " +
+			"malformed fact")
+	}
+
+	return ud.ud.SendRegisterFact(f)
+}
+
+// Confirms a fact first registered via AddFact. The confirmation ID comes from
+// AddFact while the code will come over the associated communications system
+func (ud *UserDiscovery)ConfirmFact(confirmationID, code string)error{
+	return ud.ud.SendConfirmFact(confirmationID, code)
+}
+
+// Removes a previously confirmed fact.  Will fail if the passed fact string is
+// not well formed or if the fact is not associated with this client.
+func (ud *UserDiscovery)RemoveFact(fStr string)error{
+	f, err := fact.UnstringifyFact(fStr)
+	if err !=nil{
+		return errors.WithMessage(err, "Failed to remove due to " +
+			"malformed fact")
+	}
+	return ud.ud.RemoveFact(f)
+}
+
+// SearchCallback returns the result of a search
+type SearchCallback interface {
+	Callback(contacts *ContactList, error string)
+}
+
+// Searches for the passed Facts.  The factList is the stringification of a
+// fact list object, look at /bindings/list.go for more on that object.
+// This will reject if that object is malformed. The SearchCallback will return
+// a list of contacts, each having the facts it hit against.
+// This is NOT intended to be used to search for multiple users at once, that
+// can have a privacy reduction. Instead, it is intended to be used to search
+// for a user where multiple pieces of information is known.
+func (ud UserDiscovery)Search(fl string, callback SearchCallback,
+	timeoutMS int)error{
+	factList, _, err := fact.UnstringifyFactList(fl)
+	if err!=nil{
+		return errors.WithMessage(err, "Failed to search due to " +
+			"malformed fact list")
+	}
+	timeout := time.Duration(timeoutMS)*time.Millisecond
+	cb := func(cl []contact.Contact, err error){
+		var contactList *ContactList
+		var errStr string
+		if err==nil{
+			contactList = &ContactList{list:cl}
+		}else{
+			errStr = err.Error()
+		}
+		callback.Callback(contactList, errStr)
+	}
+	return ud.ud.Search(factList, cb, timeout)
+}
+
+// SingleSearchCallback returns the result of a single search
+type SingleSearchCallback interface {
+	Callback(contact *Contact, error string)
+}
+
+// Searches for the passed Facts.  The fact is the stringification of a
+// fact object, look at /bindings/contact.go for more on that object.
+// This will reject if that object is malformed. The SearchCallback will return
+// a list of contacts, each having the facts it hit against.
+// This only searches for a single fact at a time. It is intended to make some
+// simple use cases of the API easier.
+func (ud UserDiscovery)SearchSingle(f string, callback SingleSearchCallback,
+	timeoutMS int)error{
+	fObj, err := fact.UnstringifyFact(f)
+	if err!=nil{
+		return errors.WithMessage(err, "Failed to single search due " +
+			"to malformed fact")
+	}
+	timeout := time.Duration(timeoutMS)*time.Millisecond
+	cb := func(cl []contact.Contact, err error){
+		var contact *Contact
+		var errStr string
+		if err==nil{
+			contact = &Contact{c:&cl[0]}
+		}else{
+			errStr = err.Error()
+		}
+		callback.Callback(contact, errStr)
+	}
+	return ud.ud.Search([]fact.Fact{fObj}, cb, timeout)
+}
+
+// SingleSearchCallback returns the result of a single search
+type LookupCallback interface {
+	Callback(contact *Contact, error string)
+}
+
+// Looks for the contact object associated with the given userID.  The
+// id is the byte representation of an id.
+// This will reject if that id is malformed. The LookupCallback will return
+// the associated contact if it exists.
+func (ud UserDiscovery)Lookup(idBytes []byte, callback LookupCallback,
+	timeoutMS int)error {
+
+	uid, err := id.Unmarshal(idBytes)
+	if err!=nil{
+		return errors.WithMessage(err, "Failed to lookup due to " +
+			"malformed id")
+	}
+
+	timeout := time.Duration(timeoutMS)*time.Millisecond
+	cb := func(cl contact.Contact, err error){
+		var contact *Contact
+		var errStr string
+		if err==nil{
+			contact = &Contact{c:&cl}
+		}else{
+			errStr = err.Error()
+		}
+		callback.Callback(contact, errStr)
+	}
+
+	return ud.ud.Lookup(uid, cb, timeout)
+
+}
\ No newline at end of file
diff --git a/ud/addFact.go b/ud/addFact.go
index a20626303b0baebe980bfe02777ad2ecebf9af76..11bf3395658b8e07073a44e6dc0ec1c4edd1ea83 100644
--- a/ud/addFact.go
+++ b/ud/addFact.go
@@ -10,27 +10,37 @@ import (
 	"gitlab.com/xx_network/comms/connect"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
+	jww "github.com/spf13/jwalterweatherman"
 )
 
 type addFactComms interface {
 	SendRegisterFact(host *connect.Host, message *pb.FactRegisterRequest) (*pb.FactRegisterResponse, error)
 }
 
-func (m *Manager) SendRegisterFact(fact fact.Fact) (*pb.FactRegisterResponse, error) {
+// Adds a fact for the user to user discovery. Will only succeed if the
+// user is already registered and the system does not have the fact currently
+// registered for any user.
+// This does not complete the fact registration process, it returns a
+// confirmation id instead. Over the communications system the fact is
+// associated with, a code will be sent. This confirmation ID needs to be
+// called along with the code to finalize the fact.
+func (m *Manager) SendRegisterFact(fact fact.Fact) (string, error) {
+	jww.INFO.Printf("ud.SendRegisterFact(%s)", fact.Stringify())
 	uid := m.storage.User().GetCryptographicIdentity().GetUserID()
 	return m.addFact(fact, uid, m.comms)
 }
 
-func (m *Manager) addFact(inFact fact.Fact, uid *id.ID, aFC addFactComms) (*pb.FactRegisterResponse, error) {
+func (m *Manager) addFact(inFact fact.Fact, uid *id.ID, aFC addFactComms) (string, error) {
+
 	if !m.IsRegistered() {
-		return nil, errors.New("Failed to add fact: " +
+		return "", errors.New("Failed to add fact: " +
 			"client is not registered")
 	}
 
 	// Create a primitives Fact so we can hash it
 	f, err := fact.NewFact(inFact.T, inFact.Fact)
 	if err != nil {
-		return &pb.FactRegisterResponse{}, err
+		return "", err
 	}
 
 	// Create a hash of our fact
@@ -39,7 +49,7 @@ func (m *Manager) addFact(inFact fact.Fact, uid *id.ID, aFC addFactComms) (*pb.F
 	// Sign our inFact for putting into the request
 	fsig, err := rsa.Sign(rand.Reader, m.privKey, hash.CMixHash, fhash, nil)
 	if err != nil {
-		return &pb.FactRegisterResponse{}, err
+		return "", err
 	}
 
 	// Create our Fact Removal Request message data
@@ -55,6 +65,11 @@ func (m *Manager) addFact(inFact fact.Fact, uid *id.ID, aFC addFactComms) (*pb.F
 	// Send the message
 	response, err := aFC.SendRegisterFact(m.host, &remFactMsg)
 
+	confirmationID := ""
+	if response!=nil{
+		confirmationID=response.ConfirmationID
+	}
+
 	// Return the error
-	return response, err
+	return confirmationID, err
 }
diff --git a/ud/confirmFact.go b/ud/confirmFact.go
index de56805f668bd8deac98620dc9ccd88a20bb5c65..b715a620d19af1c3f3cdb9f4c25599334f70c277 100644
--- a/ud/confirmFact.go
+++ b/ud/confirmFact.go
@@ -5,13 +5,17 @@ import (
 	pb "gitlab.com/elixxir/comms/mixmessages"
 	"gitlab.com/xx_network/comms/connect"
 	"gitlab.com/xx_network/comms/messages"
+	jww "github.com/spf13/jwalterweatherman"
 )
 
 type confirmFactComm interface {
 	SendConfirmFact(host *connect.Host, message *pb.FactConfirmRequest) (*messages.Ack, error)
 }
 
+// Confirms a fact first registered via AddFact. The confirmation ID comes from
+// AddFact while the code will come over the associated communications system
 func (m *Manager) SendConfirmFact(confirmationID, code string) error {
+	jww.INFO.Printf("ud.SendConfirmFact(%s, %s)", confirmationID, code)
 	if err := m.confirmFact(confirmationID, code, m.comms); err!=nil{
 		return errors.WithMessage(err, "Failed to confirm fact")
 	}
diff --git a/ud/lookup.go b/ud/lookup.go
index 15eff9f0dd9b0d55ac665eff64bea35ef32bb66c..3d57fcda5023bb6f6d9dfa2efa291a0cf7cfe10f 100644
--- a/ud/lookup.go
+++ b/ud/lookup.go
@@ -56,7 +56,7 @@ func (m *Manager) lookupProcess(c chan message.Receive, quitCh <-chan struct{})
 // Lookup returns the public key of the passed ID as known by the user discovery
 // system or returns by the timeout.
 func (m *Manager) Lookup(uid *id.ID, callback lookupCallback, timeout time.Duration) error {
-
+	jww.INFO.Printf("ud.Lookup(%s, %s)", uid, timeout)
 	if !m.IsRegistered(){
 		return errors.New("Failed to lookup: " +
 			"client is not registered")
diff --git a/ud/manager.go b/ud/manager.go
index 7cbce3d6b793ea26a9a47fee81afff4137cd7c33..733a2149b262c1198a12347f1e90a82f070cf35a 100644
--- a/ud/manager.go
+++ b/ud/manager.go
@@ -14,6 +14,7 @@ import (
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
 	"sync"
+	jww "github.com/spf13/jwalterweatherman"
 )
 
 type Manager struct {
@@ -48,7 +49,7 @@ type Manager struct {
 // New manager builds a new user discovery manager. It requires that an
 // updated NDF is available and will error if one is not.
 func NewManager(client *api.Client)(*Manager, error){
-
+	jww.INFO.Println("ud.NewManager()")
 	if !client.GetHealth().IsHealthy(){
 		return nil, errors.New("cannot start UD Manager when network " +
 			"is not healthy")
diff --git a/ud/register.go b/ud/register.go
index bac83720391e896f154dc8e9e6f9825048dbaf5c..90832d6e5d9a036b260a920a284fe0c897c84e68 100644
--- a/ud/register.go
+++ b/ud/register.go
@@ -9,14 +9,20 @@ import (
 	"gitlab.com/xx_network/comms/connect"
 	"gitlab.com/xx_network/comms/messages"
 	"gitlab.com/xx_network/crypto/signature/rsa"
+	jww "github.com/spf13/jwalterweatherman"
 )
 
 type registerUserComms interface {
 	SendRegisterUser(*connect.Host, *pb.UDBUserRegistration) (*messages.Ack, error)
 }
 
-// Register registers a user with user discovery.
+// Register registers a user with user discovery. Will return an error if the
+// network signatures are malformed or if the username is taken. Usernames cannot
+// be changed after registration at this time. Will fail if the user is already
+// registered.
+// Registration does not go over cmix, it occurs over normal communications
 func (m *Manager) Register(username string) error {
+	jww.INFO.Printf("ud.Register(%s)", username)
 	return m.register(username, m.comms)
 }
 
diff --git a/ud/remove.go b/ud/remove.go
index 147cf49642a0852f005eafa1e4ceb78f411dc9bb..d679a1abd479230ae2baa9e6dc59a6d49c07fcd5 100644
--- a/ud/remove.go
+++ b/ud/remove.go
@@ -6,13 +6,17 @@ import (
 	"gitlab.com/elixxir/primitives/fact"
 	"gitlab.com/xx_network/comms/connect"
 	"gitlab.com/xx_network/comms/messages"
+	jww "github.com/spf13/jwalterweatherman"
 )
 
 type removeFactComms interface {
 	SendDeleteMessage(host *connect.Host, message *mixmessages.FactRemovalRequest) (*messages.Ack, error)
 }
 
+// Removes a previously confirmed fact.  Will fail if the fact is not
+// associated with this client.
 func (m *Manager) RemoveFact(fact fact.Fact) error {
+	jww.INFO.Printf("ud.RemoveFact(%s)", fact.Stringify())
 	return m.removeFact(fact, nil)
 }
 
diff --git a/ud/search.go b/ud/search.go
index ad180a64d1ed8c2b17dab80a108e3dbc5d230c04..be2321322ec324942ee9759bb5a5e3e80368fdeb 100644
--- a/ud/search.go
+++ b/ud/search.go
@@ -16,7 +16,7 @@ import (
 	"time"
 )
 
-type searchCallback func([]contact.Contact, error)
+type SearchCallback func([]contact.Contact, error)
 
 func (m *Manager) searchProcess(c chan message.Receive, quitCh <-chan struct{}) {
 	for true {
@@ -54,8 +54,13 @@ func (m *Manager) searchProcess(c chan message.Receive, quitCh <-chan struct{})
 	}
 }
 
-// Search...
-func (m *Manager) Search(list fact.FactList, callback searchCallback, timeout time.Duration) error {
+// Searches for the passed Facts. The SearchCallback will return
+// a list of contacts, each having the facts it hit against.
+// This is NOT intended to be used to search for multiple users at once, that
+// can have a privacy reduction. Instead, it is intended to be used to search
+// for a user where multiple pieces of information is known.
+func (m *Manager) Search(list fact.FactList, callback SearchCallback, timeout time.Duration) error {
+	jww.INFO.Printf("ud.Search(%s, %s)", list.Stringify(), timeout)
 	if !m.IsRegistered() {
 		return errors.New("Failed to search: " +
 			"client is not registered")