Skip to main content
When a user tries to link a login method that’s already linked to a different Privy user, the SDK surfaces a transfer conflict instead of failing outright. Your app can catch this conflict, confirm the transfer with the user, and re-submit the login method to move it onto the currently authenticated account.
Programmatic account transfer is currently available on the Privy iOS and Android native SDKs only.
Login method transfer must be enabled in your dashboard under User management > Authentication > Login method transfer before the SDK will surface transfer conflicts. See Configure account transfer for background on the underlying flow, including the current limitation that the orphaned account must have only one login method.

How it works

  1. Your app calls a link (or linkWithCode) method for email, SMS, OAuth, SIWE, or SIWS.
  2. If that login method is already linked to a different Privy user who has no other login methods, the call fails with a transfer conflict instead of a generic link error. The conflict carries a one-time nonce and ConflictingUserMetadata describing the other account.
  3. Your app shows a confirmation prompt (e.g. “Transfer this email from display name?”) using the metadata.
  4. If the user confirms, your app re-proves ownership of the login method (resubmit the OTP code, redo the OAuth flow, or re-sign the SIWE/SIWS message) and calls the corresponding transferWithCode/transferAccount method with the nonce.
  5. On success, the login method moves to the current user, and the orphaned account is deleted.
Transferring an account only moves the login method itself. It does not transfer any embedded wallet from the orphaned account — that wallet, if any, remains with the deleted account’s assets orphaned along with it. Don’t let users trigger a transfer without warning them about this if the conflicting account might hold funds.

Catching the transfer conflict

On iOS, a transfer conflict is thrown as a PrivyError with errorCode .authenticationFailure(.accountTransferRequired(nonce:conflictingUser:)):

ConflictingUserMetadata

Use these fields only to render the confirmation prompt. They identify a different Privy user, so avoid logging, persisting, or sending them to analytics.

Transferring by login method

Each method requires you to re-prove ownership of the login method before the transfer nonce is accepted — a stale OTP code or signature won’t work, so re-collect it after the user confirms.

Email

The nonce is tied to a fresh OTP, so send a new code to the same email address before calling transferWithCode — the code from the original linkWithCode attempt won’t work.

SMS

The nonce is tied to a fresh OTP, so send a new code to the same phone number before calling transferWithCode — the code from the original linkWithCode attempt won’t work.

OAuth

A fresh OAuth browser flow must run to produce new credentials before the transfer can complete.

SIWE (Sign-In with Ethereum)

Generate a fresh SIWE message and signature — don’t reuse the one from the original link call.

SIWS (Sign-In with Solana)

Generate a fresh SIWS message and signature — don’t reuse the one from the original link call.
If the transfer call itself fails (e.g. the nonce expired), surface a normal error and let the user restart the link flow from the beginning — nonces are one-time use and tied to the credentials submitted alongside them.