diff --git a/api/authenticatedChannel.go b/api/authenticatedChannel.go
index 0af89ff00d7f87f5590d55f4b2dfcd2788d013d0..88682af983c107345b6415648bec9558f2eb4d6b 100644
--- a/api/authenticatedChannel.go
+++ b/api/authenticatedChannel.go
@@ -20,16 +20,17 @@ import (
 // RequestAuthenticatedChannel sends a request to another party to establish an
 // authenticated channel
 // It will not run if the network status is not healthy
-// An error will be returned if a channel already exists, if a request was
-// already received, or if a request was already sent
+// An error will be returned if a channel already exists or if a request was
+// already received
 // When a confirmation occurs, the channel will be created and the callback
 // will be called
+// Can be retried.
 func (c *Client) RequestAuthenticatedChannel(recipient, me contact.Contact,
-	message string) error {
+	message string) (id.Round, error) {
 	jww.INFO.Printf("RequestAuthenticatedChannel(%s)", recipient.ID)
 
 	if !c.network.GetHealthTracker().IsHealthy() {
-		return errors.New("Cannot request authenticated channel " +
+		return 0, errors.New("Cannot request authenticated channel " +
 			"creation when the network is not healthy")
 	}
 
@@ -60,11 +61,12 @@ func (c *Client) GetAuthenticatedChannelRequest(partner *id.ID) (contact.Contact
 // An error will be returned if a channel already exists, if a request doest
 // exist, or if the passed in contact does not exactly match the received
 // request
-func (c *Client) ConfirmAuthenticatedChannel(recipient contact.Contact) error {
+// Can be retried.
+func (c *Client) ConfirmAuthenticatedChannel(recipient contact.Contact) (id.Round, error) {
 	jww.INFO.Printf("ConfirmAuthenticatedChannel(%s)", recipient.ID)
 
 	if !c.network.GetHealthTracker().IsHealthy() {
-		return errors.New("Cannot request authenticated channel " +
+		return 0, errors.New("Cannot request authenticated channel " +
 			"creation when the network is not healthy")
 	}
 
diff --git a/api/client.go b/api/client.go
index e70241ec757547aa7c3c81291cad52dd70aec947..ae87fdc6dc36a974875f5a73ddea87ed52fbded1 100644
--- a/api/client.go
+++ b/api/client.go
@@ -84,33 +84,12 @@ func NewClient(ndfJSON, storageDir string, password []byte, registrationCode str
 
 	protoUser := createNewUser(rngStream, cmixGrp, e2eGrp)
 
-	// Get current client version
-	currentVersion, err := version.ParseVersion(SEMVER)
-	if err != nil {
-		return errors.WithMessage(err, "Could not parse version string.")
-	}
-
-	// Create Storage
-	passwordStr := string(password)
-	storageSess, err := storage.New(storageDir, passwordStr, protoUser,
-		currentVersion, cmixGrp, e2eGrp, rngStreamGen)
+	err = checkVersionAndSetupStorage(def, storageDir, password, protoUser,
+		cmixGrp, e2eGrp, rngStreamGen, false, registrationCode)
 	if err != nil {
 		return err
 	}
 
-	// Save NDF to be used in the future
-	storageSess.SetBaseNDF(def)
-
-	//store the registration code for later use
-	storageSess.SetRegCode(registrationCode)
-
-	//move the registration state to keys generated
-	err = storageSess.ForwardRegistrationStatus(storage.KeyGenComplete)
-	if err != nil {
-		return errors.WithMessage(err, "Failed to denote state "+
-			"change in session")
-	}
-
 	//TODO: close the session
 	return nil
 }
@@ -135,29 +114,39 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password [
 
 	protoUser := createPrecannedUser(precannedID, rngStream, cmixGrp, e2eGrp)
 
-	// Get current client version
-	currentVersion, err := version.ParseVersion(SEMVER)
+	err = checkVersionAndSetupStorage(def, storageDir, password, protoUser,
+		cmixGrp, e2eGrp, rngStreamGen, true, "")
 	if err != nil {
-		return errors.WithMessage(err, "Could not parse version string.")
+		return err
 	}
+	//TODO: close the session
+	return nil
+}
 
-	// Create Storage
-	passwordStr := string(password)
-	storageSess, err := storage.New(storageDir, passwordStr, protoUser,
-		currentVersion, cmixGrp, e2eGrp, rngStreamGen)
+// NewVanityClient creates a user with a receptionID that starts with the supplied prefix
+// It creates client storage, generates keys, connects, and registers
+// with the network. Note that this does not register a username/identity, but
+// merely creates a new cryptographic identity for adding such information
+// at a later date.
+func NewVanityClient(ndfJSON, storageDir string, password []byte, registrationCode string, userIdPrefix string) error {
+	jww.INFO.Printf("NewVanityClient()")
+	// Use fastRNG for RNG ops (AES fortuna based RNG using system RNG)
+	rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG)
+	rngStream := rngStreamGen.GetStream()
+
+	// Parse the NDF
+	def, err := parseNDF(ndfJSON)
 	if err != nil {
 		return err
 	}
+	cmixGrp, e2eGrp := decodeGroups(def)
 
-	// Save NDF to be used in the future
-	storageSess.SetBaseNDF(def)
+	protoUser := createNewVanityUser(rngStream, cmixGrp, e2eGrp, userIdPrefix)
 
-	//move the registration state to indicate registered with permissioning
-	err = storageSess.ForwardRegistrationStatus(
-		storage.PermissioningComplete)
+	err = checkVersionAndSetupStorage(def, storageDir, password, protoUser,
+		cmixGrp, e2eGrp, rngStreamGen, false, registrationCode)
 	if err != nil {
-		return errors.WithMessage(err, "Failed to denote state "+
-			"change in session")
+		return err
 	}
 
 	//TODO: close the session
@@ -583,3 +572,43 @@ func decodeGroups(ndf *ndf.NetworkDefinition) (cmixGrp, e2eGrp *cyclic.Group) {
 
 	return cmixGrp, e2eGrp
 }
+
+// checkVersionAndSetupStorage is common code shared by NewClient, NewPrecannedClient and NewVanityClient
+// it checks client version and creates a new storage for user data
+func checkVersionAndSetupStorage(def *ndf.NetworkDefinition, storageDir string, password []byte,
+	protoUser user.User, cmixGrp, e2eGrp *cyclic.Group, rngStreamGen *fastRNG.StreamGenerator,
+	isPrecanned bool, registrationCode string) error {
+	// Get current client version
+	currentVersion, err := version.ParseVersion(SEMVER)
+	if err != nil {
+		return errors.WithMessage(err, "Could not parse version string.")
+	}
+
+	// Create Storage
+	passwordStr := string(password)
+	storageSess, err := storage.New(storageDir, passwordStr, protoUser,
+		currentVersion, cmixGrp, e2eGrp, rngStreamGen)
+	if err != nil {
+		return err
+	}
+
+	// Save NDF to be used in the future
+	storageSess.SetBaseNDF(def)
+
+	if !isPrecanned {
+		//store the registration code for later use
+		storageSess.SetRegCode(registrationCode)
+		//move the registration state to keys generated
+		err = storageSess.ForwardRegistrationStatus(storage.KeyGenComplete)
+	} else {
+		//move the registration state to indicate registered with permissioning
+		err = storageSess.ForwardRegistrationStatus(storage.PermissioningComplete)
+	}
+
+	if err != nil {
+		return errors.WithMessage(err, "Failed to denote state "+
+			"change in session")
+	}
+
+	return nil
+}
diff --git a/api/user.go b/api/user.go
index 892d84c63c8fb0e29001774c6c645f351b3d00b8..48d7f992dfa32b48a3905752c55459ddc710e701 100644
--- a/api/user.go
+++ b/api/user.go
@@ -17,6 +17,10 @@ import (
 	"gitlab.com/xx_network/crypto/xx"
 	"gitlab.com/xx_network/primitives/id"
 	"math/rand"
+	"regexp"
+	"runtime"
+	"strings"
+	"sync"
 )
 
 const (
@@ -134,3 +138,126 @@ func createPrecannedUser(precannedID uint, rng csprng.Source, cmix, e2e *cyclic.
 		ReceptionRSA:     rsaKey,
 	}
 }
+
+// createNewVanityUser generates an identity for cMix
+// The identity's ReceptionID is not random but starts with the supplied prefix 
+func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix string) user.User {
+	// CMIX Keygen
+	// FIXME: Why 256 bits? -- this is spec but not explained, it has
+	// to do with optimizing operations on one side and still preserves
+	// decent security -- cite this.
+	cMixKeyBytes, err := csprng.GenerateInGroup(cmix.GetPBytes(), 256, rng)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+
+	// DH Keygen
+	// FIXME: Why 256 bits? -- this is spec but not explained, it has
+	// to do with optimizing operations on one side and still preserves
+	// decent security -- cite this. Why valid for BOTH e2e and cmix?
+	e2eKeyBytes, err := csprng.GenerateInGroup(e2e.GetPBytes(), 256, rng)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+
+	// RSA Keygen (4096 bit defaults)
+	transmissionRsaKey, err := rsa.GenerateKey(rng, rsa.DefaultRSABitLen)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+
+	// Salt, UID, etc gen
+	transmissionSalt := make([]byte, SaltSize)
+	n, err := csprng.NewSystemRNG().Read(transmissionSalt)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+	if n != SaltSize {
+		jww.FATAL.Panicf("transmissionSalt size too small: %d", n)
+	}
+	transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(), transmissionSalt, id.User)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+
+	receptionRsaKey, err := rsa.GenerateKey(rng, rsa.DefaultRSABitLen)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+
+	var mu sync.Mutex // just in case more than one go routine tries to access receptionSalt and receptionID
+	done := make(chan struct{}) 
+	found:= make(chan bool)
+	wg:= &sync.WaitGroup{}
+	cores := runtime.NumCPU()
+
+	var receptionSalt []byte
+	var receptionID *id.ID 
+	
+	pref := prefix
+	ignoreCase := false
+	// check if case-insensitivity is enabled
+	if strings.HasPrefix(prefix, "(?i)") {
+		pref = strings.ToLower(pref[4:])
+		ignoreCase = true
+	}
+	// Check if prefix contains valid Base64 characters
+	match, _ := regexp.MatchString("^[A-Za-z0-9+/]+$", pref)
+	if match == false {
+		jww.FATAL.Panicf("Prefix contains non-Base64 characters")
+	}
+	jww.INFO.Printf("Vanity userID generation started. Prefix: %s Ignore-Case: %v NumCPU: %d", pref, ignoreCase, cores)
+	for w := 0; w < cores; w++{
+		wg.Add(1)
+		go func() {
+			rSalt := make([]byte, SaltSize)
+			for {	
+				select {
+				case <- done:
+					defer wg.Done()
+					return
+				default:
+					n, err = csprng.NewSystemRNG().Read(rSalt)
+					if err != nil {
+						jww.FATAL.Panicf(err.Error())
+					}
+					if n != SaltSize {
+						jww.FATAL.Panicf("receptionSalt size too small: %d", n)
+					}
+					rID, err := xx.NewID(receptionRsaKey.GetPublic(), rSalt, id.User)
+					if err != nil {
+						jww.FATAL.Panicf(err.Error())
+					}
+					id := rID.String()
+					if ignoreCase {
+						id = strings.ToLower(id)
+					} 
+					if strings.HasPrefix(id, pref) {
+						mu.Lock()
+						receptionID = rID
+						receptionSalt = rSalt
+						mu.Unlock()
+						found <- true
+						defer wg.Done()
+						return
+					}
+				}	
+			}
+		}()
+	}
+	// wait for a solution then close the done channel to signal the workers to exit
+	<- found
+	close(done)
+	wg.Wait()
+	return user.User{
+		TransmissionID:   transmissionID.DeepCopy(),
+		TransmissionSalt: transmissionSalt,
+		TransmissionRSA:  transmissionRsaKey,
+		ReceptionID:      receptionID.DeepCopy(),
+		ReceptionSalt:    receptionSalt,
+		ReceptionRSA:     receptionRsaKey,
+		Precanned:        false,
+		CmixDhPrivateKey: cmix.NewIntFromBytes(cMixKeyBytes),
+		E2eDhPrivateKey:  e2e.NewIntFromBytes(e2eKeyBytes),
+	}
+}
diff --git a/auth/confirm.go b/auth/confirm.go
index fee1433a2c22b7323cb5c1ce9d1ea57c6108c9a4..d91f81e33e9e1d52aac5136e620ec405842ccd24 100644
--- a/auth/confirm.go
+++ b/auth/confirm.go
@@ -12,26 +12,23 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/interfaces"
 	"gitlab.com/elixxir/client/interfaces/params"
-	"gitlab.com/elixxir/client/interfaces/utility"
 	"gitlab.com/elixxir/client/storage"
-	ds "gitlab.com/elixxir/comms/network/dataStructures"
+	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/elixxir/crypto/diffieHellman"
 	cAuth "gitlab.com/elixxir/crypto/e2e/auth"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/elixxir/primitives/states"
 	"io"
-	"time"
 )
 
 func ConfirmRequestAuth(partner contact.Contact, rng io.Reader,
-	storage *storage.Session, net interfaces.NetworkManager) error {
+	storage *storage.Session, net interfaces.NetworkManager) (id.Round, error) {
 
 	/*edge checking*/
 
 	// check that messages can be sent over the network
 	if !net.GetHealthTracker().IsHealthy() {
-		return errors.New("Cannot confirm authenticated message " +
+		return 0, errors.New("Cannot confirm authenticated message " +
 			"when the network is not healthy")
 	}
 
@@ -40,14 +37,14 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader,
 	// the lock
 	storedContact, err := storage.Auth().GetReceivedRequest(partner.ID)
 	if err != nil {
-		return errors.Errorf("failed to find a pending Auth Request: %s",
+		return 0, errors.Errorf("failed to find a pending Auth Request: %s",
 			err)
 	}
 
 	// verify the passed contact matches what is stored
 	if storedContact.DhPubKey.Cmp(partner.DhPubKey) != 0 {
 		storage.Auth().Fail(partner.ID)
-		return errors.WithMessage(err, "Pending Auth Request has different "+
+		return 0, errors.WithMessage(err, "Pending Auth Request has different "+
 			"pubkey than stored")
 	}
 
@@ -68,7 +65,7 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader,
 	_, err = rng.Read(salt)
 	if err != nil {
 		storage.Auth().Fail(partner.ID)
-		return errors.Wrap(err, "Failed to generate salt for "+
+		return 0, errors.Wrap(err, "Failed to generate salt for "+
 			"confirmation")
 	}
 
@@ -108,21 +105,19 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader,
 	if err := storage.E2e().AddPartner(partner.ID, partner.DhPubKey, newPrivKey,
 		p, p); err != nil {
 		storage.Auth().Fail(partner.ID)
-		return errors.Errorf("Failed to create channel with partner (%s) "+
+		return 0, errors.Errorf("Failed to create channel with partner (%s) "+
 			"on confirmation: %+v",
 			partner.ID, err)
 	}
 
 	// delete the in progress negotiation
 	// this unlocks the request lock
-	if err := storage.Auth().Delete(partner.ID); err != nil {
-		return errors.Errorf("UNRECOVERABLE! Failed to delete in "+
+	//fixme - do these deletes at a later date
+	/*if err := storage.Auth().Delete(partner.ID); err != nil {
+		return 0, errors.Errorf("UNRECOVERABLE! Failed to delete in "+
 			"progress negotiation with partner (%s) after creating confirmation: %+v",
 			partner.ID, err)
-	}
-
-	//store the message as a critical message so it will always be sent
-	storage.GetCriticalRawMessages().AddProcessing(cmixMsg, partner.ID)
+	}*/
 
 	jww.INFO.Printf("Confirming Auth with %s, msgDigest: %s",
 		partner.ID, cmixMsg.Digest())
@@ -134,39 +129,11 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader,
 		// retried
 		jww.INFO.Printf("Auth Confirm with %s (msgDigest: %s) failed "+
 			"to transmit: %+v", partner.ID, cmixMsg.Digest(), err)
-		storage.GetCriticalRawMessages().Failed(cmixMsg, partner.ID)
-		return errors.WithMessage(err, "Auth Confirm Failed to transmit")
+		return 0, errors.WithMessage(err, "Auth Confirm Failed to transmit")
 	}
 
 	jww.INFO.Printf("Confirm Request with %s (msgDigest: %s) sent on round %d",
 		partner.ID, cmixMsg.Digest(), round)
 
-	/*check message delivery*/
-	sendResults := make(chan ds.EventReturn, 1)
-	roundEvents := net.GetInstance().GetRoundEvents()
-
-	roundEvents.AddRoundEventChan(round, sendResults, 1*time.Minute,
-		states.COMPLETED, states.FAILED)
-
-	success, numFailed, _ := utility.TrackResults(sendResults, 1)
-	if !success {
-		if numFailed > 0 {
-			jww.INFO.Printf("Auth Confirm with %s (msgDigest: %s) failed "+
-				"delivery due to round failure, will retry on reconnect",
-				partner.ID, cmixMsg.Digest())
-		} else {
-			jww.INFO.Printf("Auth Confirm with %s (msgDigest: %s) failed "+
-				"delivery due to timeout, will retry on reconnect",
-				partner.ID, cmixMsg.Digest())
-		}
-		jww.ERROR.Printf("auth confirm failed to transmit, will be " +
-			"handled on reconnect")
-		storage.GetCriticalRawMessages().Failed(cmixMsg, partner.ID)
-	} else {
-		jww.INFO.Printf("Auth Confirm with %s (msgDigest: %s) delivered "+
-			"sucesfully", partner.ID, cmixMsg.Digest())
-		storage.GetCriticalRawMessages().Succeeded(cmixMsg, partner.ID)
-	}
-
-	return nil
+	return round, nil
 }
diff --git a/auth/request.go b/auth/request.go
index 7c963123b49dd532734871c687277a318887093d..c43707904f835b19d1e64ba53cb4ec9fe550355f 100644
--- a/auth/request.go
+++ b/auth/request.go
@@ -12,59 +12,59 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/interfaces"
 	"gitlab.com/elixxir/client/interfaces/params"
-	"gitlab.com/elixxir/client/interfaces/utility"
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/client/storage/auth"
 	"gitlab.com/elixxir/client/storage/e2e"
-	ds "gitlab.com/elixxir/comms/network/dataStructures"
 	"gitlab.com/elixxir/crypto/contact"
+	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/diffieHellman"
 	cAuth "gitlab.com/elixxir/crypto/e2e/auth"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/elixxir/primitives/states"
+	"gitlab.com/xx_network/primitives/id"
 	"io"
 	"strings"
-	"time"
 )
 
 const terminator = ";"
 
 func RequestAuth(partner, me contact.Contact, message string, rng io.Reader,
-	storage *storage.Session, net interfaces.NetworkManager) error {
+	storage *storage.Session, net interfaces.NetworkManager) (id.Round, error) {
 	/*edge checks generation*/
 
 	// check that an authenticated channel does not already exists
 	if _, err := storage.E2e().GetPartner(partner.ID); err == nil ||
 		!strings.Contains(err.Error(), e2e.NoPartnerErrorStr) {
-		return errors.Errorf("Authenticated channel already " +
+		return 0, errors.Errorf("Authenticated channel already " +
 			"established with partner")
 	}
 
 	// check that the request is being sent from the proper ID
 	if !me.ID.Cmp(storage.GetUser().ReceptionID) {
-		return errors.Errorf("Authenticated channel request " +
+		return 0, errors.Errorf("Authenticated channel request " +
 			"can only be sent from user's identity")
 	}
 
 	// check that the message is properly formed
 	if strings.Contains(message, terminator) {
-		return errors.Errorf("Message cannot contain '%s'", terminator)
+		return 0, errors.Errorf("Message cannot contain '%s'", terminator)
 	}
 
+	//denote if this is a resend of an old request
+	resend := false
+
 	//lookup if an ongoing request is occurring
-	rqType, _, _, err := storage.Auth().GetRequest(partner.ID)
-	if err != nil && strings.Contains(err.Error(), auth.NoRequest) {
-		err = nil
-	}
-	if err != nil {
+	rqType, sr, _, err := storage.Auth().GetRequest(partner.ID)
+
+	if err != nil && !strings.Contains(err.Error(), auth.NoRequest){
 		if rqType == auth.Receive {
-			return errors.WithMessage(err,
-				"Cannot send a request after "+
-					"receiving a request")
+			return 0, errors.WithMessage(err,
+				"Cannot send a request after receiving a request")
 		} else if rqType == auth.Sent {
-			return errors.WithMessage(err,
-				"Cannot send a request after "+
-					"already sending one")
+			resend = true
+		}else{
+			return 0, errors.WithMessage(err,
+				"Cannot send a request after receiving unknown error " +
+				"on requesting contact status")
 		}
 	}
 
@@ -76,7 +76,7 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader,
 	ecrFmt := newEcrFormat(baseFmt.GetEcrPayloadLen())
 	requestFmt, err := newRequestFormat(ecrFmt)
 	if err != nil {
-		return errors.Errorf("failed to make request format: %+v", err)
+		return 0, errors.Errorf("failed to make request format: %+v", err)
 	}
 
 	//check the payload fits
@@ -85,7 +85,7 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader,
 	msgPayloadBytes := []byte(msgPayload)
 
 	if len(msgPayloadBytes) > requestFmt.MsgPayloadLen() {
-		return errors.Errorf("Combined message longer than space "+
+		return 0, errors.Errorf("Combined message longer than space "+
 			"available in payload; available: %v, length: %v",
 			requestFmt.MsgPayloadLen(), len(msgPayloadBytes))
 	}
@@ -95,17 +95,27 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader,
 	salt := make([]byte, saltSize)
 	_, err = rng.Read(salt)
 	if err != nil {
-		return errors.Wrap(err, "Failed to generate salt")
+		return 0, errors.Wrap(err, "Failed to generate salt")
+	}
+
+	var newPrivKey, newPubKey *cyclic.Int
+
+	// in this case we have an ongoing request so we can resend the extant
+	// request
+	if resend{
+		newPrivKey = sr.GetMyPrivKey()
+		newPubKey = sr.GetMyPubKey()
+	//in this case it is a new request and we must generate new keys
+	}else{
+		//generate new keypair
+		newPrivKey = diffieHellman.GeneratePrivateKey(256, grp, rng)
+		newPubKey = diffieHellman.GeneratePublicKey(newPrivKey, grp)
 	}
 
 	//generate ownership proof
 	ownership := cAuth.MakeOwnershipProof(storage.E2e().GetDHPrivateKey(),
 		partner.DhPubKey, storage.E2e().GetGroup())
 
-	//generate new keypair
-	newPrivKey := diffieHellman.GeneratePrivateKey(256, grp, rng)
-	newPubKey := diffieHellman.GeneratePublicKey(newPrivKey, grp)
-
 	jww.TRACE.Printf("RequestAuth MYPUBKEY: %v", newPubKey.Bytes())
 	jww.TRACE.Printf("RequestAuth THEIRPUBKEY: %v", partner.DhPubKey.Bytes())
 
@@ -130,67 +140,30 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader,
 	/*store state*/
 	//fixme: channel is bricked if the first store succedes but the second fails
 	//store the in progress auth
-	err = storage.Auth().AddSent(partner.ID, partner.DhPubKey, newPrivKey,
-		newPrivKey, confirmFp)
-	if err != nil {
-		return errors.Errorf("Failed to store auth request: %s", err)
+	if !resend{
+		err = storage.Auth().AddSent(partner.ID, partner.DhPubKey, newPrivKey,
+			newPrivKey, confirmFp)
+		if err != nil {
+			return 0, errors.Errorf("Failed to store auth request: %s", err)
+		}
 	}
 
-	//store the message as a critical message so it will always be sent
-	storage.GetCriticalRawMessages().AddProcessing(cmixMsg, partner.ID)
+	jww.INFO.Printf("Requesting Auth with %s, msgDigest: %s",
+		partner.ID, cmixMsg.Digest())
 
-	go func() {
-		jww.INFO.Printf("Requesting Auth with %s, msgDigest: %s",
-			partner.ID, cmixMsg.Digest())
-
-		/*send message*/
-		round, _, err := net.SendCMIX(cmixMsg, partner.ID,
-			params.GetDefaultCMIX())
-		if err != nil {
-			// if the send fails just set it to failed, it will
-			// but automatically retried
-			jww.WARN.Printf("Auth Request with %s (msgDigest: %s)"+
-				" failed to transmit: %+v", partner.ID,
-				cmixMsg.Digest(), err)
-			storage.GetCriticalRawMessages().Failed(cmixMsg,
-				partner.ID)
-		}
+	/*send message*/
+	round, _, err := net.SendCMIX(cmixMsg, partner.ID,
+		params.GetDefaultCMIX())
+	if err != nil {
+		// if the send fails just set it to failed, it will
+		// but automatically retried
+		return 0, errors.WithMessagef(err, "Auth Request with %s " +
+			"(msgDigest: %s) failed to transmit: %+v", partner.ID,
+			cmixMsg.Digest(), err)
+	}
 
-		jww.INFO.Printf("Auth Request with %s (msgDigest: %s) sent"+
-			" on round %d", partner.ID, cmixMsg.Digest(), round)
-
-		/*check message delivery*/
-		sendResults := make(chan ds.EventReturn, 1)
-		roundEvents := net.GetInstance().GetRoundEvents()
-
-		roundEvents.AddRoundEventChan(round, sendResults, 1*time.Minute,
-			states.COMPLETED, states.FAILED)
-
-		success, numFailed, _ := utility.TrackResults(sendResults, 1)
-		if !success {
-			if numFailed > 0 {
-				jww.WARN.Printf("Auth Request with %s "+
-					"(msgDigest: %s) failed "+
-					"delivery due to round failure, "+
-					"will retry on reconnect",
-					partner.ID, cmixMsg.Digest())
-			} else {
-				jww.WARN.Printf("Auth Request with %s "+
-					"(msgDigest: %s) failed "+
-					"delivery due to timeout, "+
-					"will retry on reconnect",
-					partner.ID, cmixMsg.Digest())
-			}
-			storage.GetCriticalRawMessages().Failed(cmixMsg,
-				partner.ID)
-		} else {
-			jww.INFO.Printf("Auth Request with %s (msgDigest: %s) "+
-				"delivered sucessfully", partner.ID,
-				cmixMsg.Digest())
-			storage.GetCriticalRawMessages().Succeeded(cmixMsg,
-				partner.ID)
-		}
-	}()
+	jww.INFO.Printf("Auth Request with %s (msgDigest: %s) sent"+
+		" on round %d", partner.ID, cmixMsg.Digest(), round)
 
-	return nil
+	return round, nil
 }
diff --git a/bindings/authenticatedChannels.go b/bindings/authenticatedChannels.go
index 28784c87f944bd3d15e43b873194f968dd513971..30b12f0a1b3039fba5b18eafeff874cc7a438a60 100644
--- a/bindings/authenticatedChannels.go
+++ b/bindings/authenticatedChannels.go
@@ -27,19 +27,20 @@ func (c *Client) MakePrecannedAuthenticatedChannel(precannedID int) (*Contact, e
 // authenticated channel
 // It will not run if the network status is not healthy
 // An error will be returned if a channel already exists, if a request was
-// already received, or if a request was already sent
+// already received.
 // When a confirmation occurs, the channel will be created and the callback
 // will be called
+// This can be called many times and retried.
 //
 // This function takes the marshaled send report to ensure a memory leak does
 // not occur as a result of both sides of the bindings holding a refrence to
 // the same pointer.
 func (c *Client) RequestAuthenticatedChannel(recipientMarshaled,
-	meMarshaled []byte, message string) error {
+	meMarshaled []byte, message string) (int, error) {
 	recipent, err := contact.Unmarshal(recipientMarshaled)
 
 	if err != nil {
-		return errors.New(fmt.Sprintf("Failed to "+
+		return 0, errors.New(fmt.Sprintf("Failed to "+
 			"RequestAuthenticatedChannel: Failed to Unmarshal Recipent: "+
 			"%+v", err))
 	}
@@ -47,11 +48,13 @@ func (c *Client) RequestAuthenticatedChannel(recipientMarshaled,
 	me, err := contact.Unmarshal(meMarshaled)
 
 	if err != nil {
-		return errors.New(fmt.Sprintf("Failed to "+
+		return 0, errors.New(fmt.Sprintf("Failed to "+
 			"RequestAuthenticatedChannel: Failed to Unmarshal Me: %+v", err))
 	}
 
-	return c.api.RequestAuthenticatedChannel(recipent, me, message)
+	rid, err := c.api.RequestAuthenticatedChannel(recipent, me, message)
+
+	return int(rid), err
 }
 
 // RegisterAuthCallbacks registers both callbacks for authenticated channels.
@@ -79,19 +82,26 @@ func (c *Client) RegisterAuthCallbacks(request AuthRequestCallback,
 // received request and sends a message to the requestor that the request has
 // been confirmed
 // It will not run if the network status is not healthy
-// An error will be returned if a channel already exists, if a request doest
+// An error will be returned if a request doest
 // exist, or if the passed in contact does not exactly match the received
-// request
-func (c *Client) ConfirmAuthenticatedChannel(recipientMarshaled []byte) error {
+// request.
+// This can be called many times and retried.
+//
+// This function takes the marshaled send report to ensure a memory leak does
+// not occur as a result of both sides of the bindings holding a refrence to
+// the same pointer.
+func (c *Client) ConfirmAuthenticatedChannel(recipientMarshaled []byte) (int, error) {
 	recipent, err := contact.Unmarshal(recipientMarshaled)
 
 	if err != nil {
-		return errors.New(fmt.Sprintf("Failed to "+
+		return 0, errors.New(fmt.Sprintf("Failed to "+
 			"ConfirmAuthenticatedChannel: Failed to Unmarshal Recipient: "+
 			"%+v", err))
 	}
 
-	return c.api.ConfirmAuthenticatedChannel(recipent)
+	rid, err := c.api.ConfirmAuthenticatedChannel(recipent)
+
+	return int(rid), err
 }
 
 // VerifyOwnership checks if the ownership proof on a passed contact matches the
diff --git a/bindings/callback.go b/bindings/callback.go
index 34d26ecccaf4b4f105a2ab2e7b29d82fb1fe3728..a14cb5151358933f2f0bd6af6cdb04156ff4ac37 100644
--- a/bindings/callback.go
+++ b/bindings/callback.go
@@ -31,12 +31,19 @@ type NetworkHealthCallback interface {
 	Callback(bool)
 }
 
-// RoundEventHandler handles round events happening on the cMix network.
+// RoundEventCallback handles waiting on the exact state of a round on
+// the cMix network.
 type RoundEventCallback interface {
 	EventCallback(rid, state int, timedOut bool)
 }
 
-// RoundEventHandler handles round events happening on the cMix network.
+// RoundCompletionCallback is returned when the completion of a round is known.
+type RoundCompletionCallback interface {
+	EventCallback(rid int, success, timedOut bool)
+}
+
+// MessageDeliveryCallback gets called on the determination if all events
+// related to a message send were successful.
 type MessageDeliveryCallback interface {
 	EventCallback(msgID []byte, delivered, timedOut bool, roundResults []byte)
 }
diff --git a/bindings/client.go b/bindings/client.go
index 34fb521076fca455294824ef3104f1c67445669d..b2c94fa95f46926ae891a8e9a41cb794cbdb28c8 100644
--- a/bindings/client.go
+++ b/bindings/client.go
@@ -333,18 +333,35 @@ func (c *Client) RegisterRoundEventsHandler(rid int, cb RoundEventCallback,
 	return newRoundUnregister(roundID, ec, c.api.GetRoundEvents())
 }
 
-// RegisterMessageDeliveryCB allows the caller to get notified if the rounds a
-// message was sent in successfully completed. Under the hood, this uses the same
-// interface as RegisterRoundEventsHandler, but provides a convenient way to use
-// the interface in its most common form, looking up the result of message
-// retrieval
+// WaitForRoundCompletion allows the caller to get notified if a round
+// has completed (or failed). Under the hood, this uses an API which uses the internal
+// round data, network historical round lookup, and waiting on network events
+// to determine what has (or will) occur.
+//
+// The callbacks will return at timeoutMS if no state update occurs
+func (c *Client) WaitForRoundCompletion(roundID int,
+	rec RoundCompletionCallback, timeoutMS int) error {
+
+	f := func(allRoundsSucceeded, timedOut bool, rounds map[id.Round]api.RoundResult) {
+		rec.EventCallback(roundID, allRoundsSucceeded, timedOut)
+	}
+
+	timeout := time.Duration(timeoutMS) * time.Millisecond
+
+	return c.api.GetRoundResults([]id.Round{id.Round(roundID)}, timeout, f)
+}
+
+// WaitForMessageDelivery allows the caller to get notified if the rounds a
+// message was sent in successfully completed. Under the hood, this uses an API
+// which uses the internal round data, network historical round lookup, and
+// waiting on network events to determine what has (or will) occur.
 //
 // The callbacks will return at timeoutMS if no state update occurs
 //
 // This function takes the marshaled send report to ensure a memory leak does
 // not occur as a result of both sides of the bindings holding a reference to
 // the same pointer.
-func (c *Client) WaitForRoundCompletion(marshaledSendReport []byte,
+func (c *Client) WaitForMessageDelivery(marshaledSendReport []byte,
 	mdc MessageDeliveryCallback, timeoutMS int) error {
 
 	sr, err := UnmarshalSendReport(marshaledSendReport)
diff --git a/cmd/getndf.go b/cmd/getndf.go
index 914412093c8f1247953473c29a02edcd68346235..7ac150020c911d695f646993e3a409c18d6cb8da 100644
--- a/cmd/getndf.go
+++ b/cmd/getndf.go
@@ -18,11 +18,13 @@ import (
 	// "gitlab.com/elixxir/client/switchboard"
 	// "gitlab.com/elixxir/client/ud"
 	// "gitlab.com/elixxir/primitives/fact"
+	"gitlab.com/elixxir/client/api"
 	"gitlab.com/elixxir/comms/client"
 	"gitlab.com/xx_network/comms/connect"
 	//"time"
 	pb "gitlab.com/elixxir/comms/mixmessages"
 	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/id/ephemeral"
 	"gitlab.com/xx_network/primitives/utils"
 )
 
@@ -63,12 +65,14 @@ var getNDFCmd = &cobra.Command{
 		if gwHost != "" {
 			host, _ := connect.NewHost(&id.TempGateway, gwHost,
 				cert, params)
+			dummyID := ephemeral.ReservedIDs[0]
 			pollMsg := &pb.GatewayPoll{
 				Partial: &pb.NDFHash{
 					Hash: nil,
 				},
 				LastUpdate:  uint64(0),
-				ReceptionID: id.DummyUser.Marshal(),
+				ReceptionID: dummyID[:],
+				ClientVersion: []byte(api.SEMVER),
 			}
 			resp, err := comms.SendPoll(host, pollMsg)
 			if err != nil {
diff --git a/cmd/init.go b/cmd/init.go
index cf19521f066d1e9e878524a7ee75fd3471cf6b7c..b00f215475bfba0c513752b1d2fd01fd13cea5c8 100644
--- a/cmd/init.go
+++ b/cmd/init.go
@@ -11,6 +11,7 @@ package cmd
 import (
 	"fmt"
 	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
 	jww "github.com/spf13/jwalterweatherman"
 )
 
@@ -29,5 +30,9 @@ var initCmd = &cobra.Command{
 }
 
 func init() {
+	initCmd.Flags().StringP("userid-prefix", "", "",
+	"Desired prefix of userID to brute force when running init command. Prepend (?i) for case-insensitive. Only Base64 characters are valid.")
+	_ = viper.BindPFlag("userid-prefix", initCmd.Flags().Lookup("userid-prefix"))
+
 	rootCmd.AddCommand(initCmd)
 }
diff --git a/cmd/root.go b/cmd/root.go
index c6ea6c91425d2cf96f532287dfcbfdc387fc7639..9ff887dad0dbb4d3d6e22a649f4ca43e5039a32e 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -95,7 +95,7 @@ var rootCmd = &cobra.Command{
 				requestor contact.Contact, message string) {
 				jww.INFO.Printf("Channel Request: %s",
 					requestor.ID)
-				err := client.ConfirmAuthenticatedChannel(
+				_, err := client.ConfirmAuthenticatedChannel(
 					requestor)
 				if err != nil {
 					jww.FATAL.Panicf("%+v", err)
@@ -306,7 +306,7 @@ func createClient() *api.Client {
 	storeDir := viper.GetString("session")
 	regCode := viper.GetString("regcode")
 	precannedID := viper.GetUint("sendid")
-
+	userIDprefix := viper.GetString("userid-prefix")
 	//create a new client if none exist
 	if _, err := os.Stat(storeDir); os.IsNotExist(err) {
 		// Load NDF
@@ -320,8 +320,14 @@ func createClient() *api.Client {
 			err = api.NewPrecannedClient(precannedID,
 				string(ndfJSON), storeDir, []byte(pass))
 		} else {
-			err = api.NewClient(string(ndfJSON), storeDir,
+			if userIDprefix != "" {
+				err = api.NewVanityClient(string(ndfJSON), storeDir,
+				[]byte(pass), regCode, userIDprefix)
+			} else {
+				err = api.NewClient(string(ndfJSON), storeDir,
 				[]byte(pass), regCode)
+			}
+			
 		}
 
 		if err != nil {
@@ -399,7 +405,7 @@ func acceptChannel(client *api.Client, recipientID *id.ID) {
 	if err != nil {
 		jww.FATAL.Panicf("%+v", err)
 	}
-	err = client.ConfirmAuthenticatedChannel(
+	_, err = client.ConfirmAuthenticatedChannel(
 		recipientContact)
 	if err != nil {
 		jww.FATAL.Panicf("%+v", err)
@@ -461,7 +467,7 @@ func addAuthenticatedChannel(client *api.Client, recipientID *id.ID,
 		me := client.GetUser().GetContact()
 		jww.INFO.Printf("Requesting auth channel from: %s",
 			recipientID)
-		err := client.RequestAuthenticatedChannel(recipientContact,
+		_, err := client.RequestAuthenticatedChannel(recipientContact,
 			me, msg)
 		if err != nil {
 			jww.FATAL.Panicf("%+v", err)
diff --git a/cmd/single.go b/cmd/single.go
index 7fe8e2038ef34240bd2ee363e6f38d8d94d26ed9..15f803b11bec0f775845fdfdfb9f8292c75ea2a7 100644
--- a/cmd/single.go
+++ b/cmd/single.go
@@ -55,7 +55,7 @@ var singleCmd = &cobra.Command{
 			authMgr.AddGeneralRequestCallback(func(
 				requester contact.Contact, message string) {
 				jww.INFO.Printf("Got request: %s", requester.ID)
-				err := client.ConfirmAuthenticatedChannel(requester)
+				_, err := client.ConfirmAuthenticatedChannel(requester)
 				if err != nil {
 					jww.FATAL.Panicf("%+v", err)
 				}
diff --git a/cmd/ud.go b/cmd/ud.go
index ccefe891a4e87c2053ec62fd95e835115aa21a45..38cbecb2cd1c6572cd140b158f435fe4291500cd 100644
--- a/cmd/ud.go
+++ b/cmd/ud.go
@@ -55,7 +55,7 @@ var udCmd = &cobra.Command{
 			authMgr.AddGeneralRequestCallback(func(
 				requester contact.Contact, message string) {
 				jww.INFO.Printf("Got Request: %s", requester.ID)
-				err := client.ConfirmAuthenticatedChannel(requester)
+				_, err := client.ConfirmAuthenticatedChannel(requester)
 				if err != nil {
 					jww.FATAL.Panicf("%+v", err)
 				}