We were doing something wrong, by doing trial and error(via API) to determine if a customer exists or not.
So we tried to create a customerProfile, w/ customerPaymentProfile & this will throw error if customerProfile already exist(if its a duplicate email). Whats good here, is that customerProfileId will be returned w/ the error payload.
Now we though of using customerProfileId from error payload, to create a new payment profile for the customer, giving us some edge by reducing one DB call on our system.
The issue with our strategy, is that apparently, opaqueData will expire, when we use it to create customerProfile(w/ payment profile) even though the request failed(duplicate user error).
So resolution is to save customer info in our system, and check if it's a returning customer or not. If it is, then get customerProfileId from db, and create new customerPaymentProfile on authorize.net
One could also create customerProfile first, w/o the customerPaymentProfile. if this transaction fails, then at least you haven't used the opaqueData yet and you get the customerProfileId w/o doing any query on your db. So when you try to create a new customerPaymentProfile, you won't get error code E00114 since opaqueData isn't used yet.
lessons learned the hard way for us, but hopefully it helps someone.