diff --git a/bindings/ud.go b/bindings/ud.go
index d167e145daf1e110bf0728cf13bc28c54287538a..976321c5b33b5fd964b37dfd4c3aa5e97be66cac 100644
--- a/bindings/ud.go
+++ b/bindings/ud.go
@@ -9,6 +9,7 @@ package bindings
 
 import (
 	"encoding/json"
+	"fmt"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/single"
@@ -420,6 +421,133 @@ func LookupUD(e2eID int, udContact []byte, cb UdLookupCallback,
 	return json.Marshal(sr)
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// User Discovery MultiLookup                                                      //
+////////////////////////////////////////////////////////////////////////////////
+
+// UdMultiLookupCallback contains the callback called by MultiLookupUD that returns the
+// contacts which match the passed in IDs.
+//
+// Parameters:
+//  - contactListJSON - the JSON marshalled bytes of []contact.Contact, or nil
+//    if an error occurs.
+//
+//   JSON Example:
+//   {
+//  	"<xxc(2)F8dL9EC6gy+RMJuk3R+Au6eGExo02Wfio5cacjBcJRwDEgB7Ugdw/BAr6RkCABkWAFV1c2VybmFtZTA7c4LzV05sG+DMt+rFB0NIJg==xxc>",
+//  	"<xxc(2)eMhAi/pYkW5jCmvKE5ZaTglQb+fTo1D8NxVitr5CCFADEgB7Ugdw/BAr6RoCABkWAFV1c2VybmFtZTE7fElAa7z3IcrYrrkwNjMS2w==xxc>",
+//  	"<xxc(2)d7RJTu61Vy1lDThDMn8rYIiKSe1uXA/RCvvcIhq5Yg4DEgB7Ugdw/BAr6RsCABkWAFV1c2VybmFtZTI7N3XWrxIUpR29atpFMkcR6A==xxc>"
+//	}
+//  - failedIDs - JSON marshalled list of []*id.ID objects which failed lookup
+//  - err - any errors that occurred in the multilookup.
+type UdMultiLookupCallback interface {
+	Callback(contactListJSON []byte, failedIDs []byte, err error)
+}
+
+type lookupResp struct {
+	id      *id.ID
+	contact contact.Contact
+	err     error
+}
+
+// MultiLookupUD returns the public key of all passed in IDs as known by the
+// user discovery system or returns by the timeout.
+//
+// Parameters:
+//  - e2eID - e2e object ID in the tracker
+//  - udContact - the marshalled bytes of the contact.Contact object
+//  - lookupIds - JSON marshalled list of []*id.ID object for the users that
+//    MultiLookupUD will look up.
+//  - singleRequestParams - the JSON marshalled bytes of single.RequestParams
+//
+// Returns:
+//  - []byte - the JSON marshalled bytes of the SingleUseSendReport object,
+//    which can be passed into Cmix.WaitForRoundResult to see if the send
+//    succeeded.
+func MultiLookupUD(e2eID int, udContact []byte, cb UdMultiLookupCallback,
+	lookupIds []byte, singleRequestParamsJSON []byte) error {
+
+	// Get user from singleton
+	user, err := e2eTrackerSingleton.get(e2eID)
+	if err != nil {
+		return err
+	}
+
+	c, err := contact.Unmarshal(udContact)
+	if err != nil {
+		return err
+	}
+
+	var idList []*id.ID
+	err = json.Unmarshal(lookupIds, &idList)
+	if err != nil {
+		return err
+	}
+
+	var p single.RequestParams
+	err = json.Unmarshal(singleRequestParamsJSON, &p)
+	if err != nil {
+		return err
+	}
+
+	respCh := make(chan lookupResp, len(idList))
+	for _, uid := range idList {
+		localID := uid.DeepCopy()
+		callback := func(c contact.Contact, err error) {
+			respCh <- lookupResp{
+				id:      localID,
+				contact: c,
+				err:     err,
+			}
+		}
+		go func() {
+			_, _, err := ud.Lookup(user.api, c, callback, localID, p)
+			if err != nil {
+				respCh <- lookupResp{
+					id:      localID,
+					contact: contact.Contact{},
+					err:     err,
+				}
+			}
+		}()
+
+	}
+
+	go func() {
+		marshaledContactList := make([][]byte, 0)
+		var failedIDs []*id.ID
+		var errorString string
+		for numReturned := 0; numReturned < len(idList); numReturned++ {
+			response := <-respCh
+			if response.err != nil {
+				failedIDs = append(failedIDs, response.id)
+				marshaledContactList = append(
+					marshaledContactList, response.contact.Marshal())
+			} else {
+				errorString = errorString +
+					fmt.Sprintf("Failed to lookup id %s: %+v",
+						response.id, response.err)
+			}
+		}
+
+		marshalledFailedIds, err := json.Marshal(failedIDs)
+		if err != nil {
+			cb.Callback(nil, nil,
+				errors.WithMessage(err,
+					"Failed to marshal failed IDs"))
+		}
+
+		contactListJSON, err := json.Marshal(marshaledContactList)
+		if err != nil {
+			jww.FATAL.Panicf(
+				"Failed to marshal list of contact.Contact: %+v", err)
+		}
+		cb.Callback(contactListJSON, marshalledFailedIds, errors.New(errorString))
+	}()
+
+	return nil
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // User Discovery Search                                                      //
 ////////////////////////////////////////////////////////////////////////////////