Appearance
Importing multiple users
Privy allows you to import your users in batches via REST API to simplify the migration process. To import users, pass in an array of ImportUserInput
items which each represent a new user. You can also create a wallet with wallet pregeneration.
Once a user has been imported into Privy, if they log in, all of their imported accounts (wallet, email, etc.) will be included in their user object. If the imported user has an embedded wallet, that wallet will be available to the user upon sign in.
If you want to import a single user at a time, Privy also enables single user import.
ImportUserInput
When importing a user, you will pass an ImportUserInput
object. See the fields on the ImportUserInput
object below:
Field | Type | Description |
---|---|---|
linkedAccounts | LinkedAccount[] | An array including all of the user's linked accounts. These objects are in the same shape as the linked accounts returned by getUser . For each linked account, you must specify the type and must not include a verifiedAt timestamp. |
createEthereumWallet | boolean | (Optional) Whether to pregenerate an embedded Ethereum wallet for the imported user. Defaults to false . |
createSolanaWallet | boolean | (Optional) Whether to pregenerate an embedded Solana wallet for the imported user. Defaults to false . |
createEthereumSmartWallet | boolean | (Optional) Whether to pregenerate an embedded Smart wallet for the imported user. Defaults to false . If createEthereumSmartWallet is true , you must also explicitly set createEthereumWallet to true as well. |
TIP
Looking for the types of LinkedAccount
s?
See a list of the different account types and the data they include
Note:
- Each account should be a JSON object including all the necessary fields for that account
type
.- Valid account
type
s areapple_oauth
,'custom_auth'
,'discord_oauth'
,'farcaster'
,'github_oauth'
,'google_oauth'
,'instagram_oauth'
,'linkedin_oauth'
,'spotify_oauth'
,'telegram'
,'tiktok_oauth'
,'twitter_oauth'
,'email'
,'phone'
and'wallet'
.
- Valid account
- If importing a user with a
custom_auth
account, thecustom_auth
account must be the only element of thelinked_accounts
array. It is not permitted to import a user with acustom_auth
account and otherlinked_accounts
. - You must exclude the
verifiedAt
field. - The SDK and REST API have different naming conventions. The SDK uses camelCase and the API uses snake_case.
CustomJwtAccount
Field | Type | Description |
---|---|---|
type | 'custom_auth' | N/A |
API: custom_user_id SDK: customUserId | string | ID of user from custom auth provider. |
DiscordAccount
Field | Type | Description |
---|---|---|
type | 'discord_oauth' | N/A |
subject | string | ID of user from Discord user API response. |
email | string | Email of user from Discord user API response. |
username | string | Username of user from Discord user API response. |
(See Discord docs)
EmailAccount
Field | Type | Description |
---|---|---|
type | 'email' | N/A |
address | string | Email address of user account. |
FarcasterAccount
Field | Type | Description |
---|---|---|
type | 'farcaster' | N/A |
fid | number | FID of the user from Farcaster user API response. |
API: owner_address SDK: ownerAddress | string | Wallet address of the user from Farcaster user API response. Note that this is the Farcaster wallet address, and not the Privy embedded wallet address. |
username | string | (Optional) Username of user from Farcaster user API response. Do not include the '@'. |
API: display_name SDK: displayName | string | (Optional) Display name of user from Farcaster user API response. |
bio | string | (Optional) Bio of user from Farcaster user API response. |
API: profile_picture_url SDK: profilePictureUrl | string | (Optional) Profile picture URL of the user from Farcaster user API response. Must be a valid image URL. |
API: homepage_url SDK: homepageUrl | string | (Optional) Profile URL of the user from Farcaster user API response. |
(See Farcaster docs. Note that the Privy import interface differs slightly from the Farcaster public interface in order to maintain consistency with other Privy LinkedAccount
types.)
GithubAccount
Field | Type | Description |
---|---|---|
type | 'github_oauth' | N/A |
subject | string | ID of user from GitHub user API response. |
email | string | Email of user from GitHub user API response |
name | string | Name of user from GitHub user API response |
username | string | Username of user from GitHub user API response |
(See GitHub docs)
GoogleAccount
Field | Type | Description |
---|---|---|
type | 'google_oauth' | N/A |
subject | string | sub pulled from Google-provided JWT with "openid" scope. |
email | string | email from Google-provided JWT with "email" scope. |
name | string | name from Google-provided JWT with "profile" scope. |
InstagramAccount
Field | Type | Description |
---|---|---|
type | 'instagram_oauth' | N/A |
subject | string | ID of user from Instagram user API response. |
username | string | The name displayed on a user's profile from Instagram's /me API response. |
(See Instagram docs)
LinkedinAccount
Field | Type | Description |
---|---|---|
type | 'linkedin_oauth' | N/A |
subject | string | ID of user from LinkedIn user API response. |
email | string | Email of user from LinkedIn user API response |
name | string | Name of user from LinkedIn user API response. Do not include the '@'. |
(See Linkedin docs)
PhoneAccount
Field | Type | Description |
---|---|---|
type | 'phone' | N/A |
number | string | Phone number of user account (non-international numbers default to US). |
While number
is accepted as input, phoneNumber
is returned in the response.
SmartWalletAccount
Field | Type | Description |
---|---|---|
type | 'smart_wallet' | N/A |
address | string | Checksummed smart wallet address. |
smart_wallet_type | SmartWalletType | One of 'kernel' , 'safe' , 'biconomy' or 'light_account' |
SpotifyAccount
Field | Type | Description |
---|---|---|
type | 'spotify_oauth' | N/A |
subject | string | ID of user from Spotify user API response. |
email | string | Email of user from Spotify user API. |
name | string | The name displayed on a user's profile from Spotify display_name API response. |
(See Spotify docs)
TelegramAccount
Field | Type | Description |
---|---|---|
type | 'telegram' | N/A |
telegram_user_id | string | ID of a user's telegram account. |
first_name | string | The first name displayed on a user's telegram account. |
last_name | string | (Optional) The last name displayed on a user's telegram account. |
username | string | (Optional) The username displayed on a user's telegram account. |
photo_url | string | (Optional) The url of a user's telegram account profile picture. |
(See Telegram docs)
TwitterAccount
Field | Type | Description |
---|---|---|
type | 'twitter_oauth' | N/A |
subject | string | ID of user from Twitter user API response. |
name | string | Name of user from Twitter user API response |
username | string | Username of user from Twitter user API response. Do not include the '@'. |
API: profile_picture_url SDK: profilePictureUrl | string | (Optional) Profile picture URL of the user from Twitter user API response. Must be a valid image URL. |
(See Twitter docs)
WalletAccount
Field | Type | Description |
---|---|---|
type | 'wallet' | N/A |
API: chain_type SDK: chainType | 'ethereum' | Type of chain for the wallet. EVM chains ('ethereum' ) and Solana ('solana' ) are currently supported. |
address | string | Checksummed wallet address. |
Using the REST API
Make a POST
request to:
sh
https://auth.privy.io/api/v1/users/import
In the body of the request, include a users
field with an array of up to 20 ImportUser
objects.
Below is a sample cURL command for importing multiple new users into Privy:
bash
$ curl --request POST https://auth.privy.io/api/v1/users/import \
-u "<your-privy-app-id>:<your-privy-app-secret>" \
-H "privy-app-id: <your-privy-app-id>" \
-H "Content-Type: application/json" \
-d '{
"users": [
{
"linked_accounts": [
{
"type": "github_oauth",
"subject": "837163725915354975",
"username": "Smiles",
"name": "The Joker",
"email": "joker@gmail.com",
"profile_picture_url": "https://i.imgur.com/joker.jpg"
}
]
},
{
"linked_accounts": [
{
"type": "wallet",
"chain_type": "ethereum",
"address": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045"
}
]
},
{
"linked_accounts": [
{
"type": "phone",
"number": "18888675309"
}
]
},
{
"linked_accounts": [
{
"type": "email",
"address": "robin@gmail.com"
}
]
}
]
}'
Rest API response
A successful response will include a list of results along with a few aggregates displaying the number of created, number of failed, and total number of users.
A result can either be successful or unsuccessful. This will be a CreateResultSuccess
or CreateResultFailure
object respectively; you can see the types for these objects below. A "success" status code from the API (e.g. 200
) does not imply that all imports necessarily succeeded.
See the types for CreateResult
objects
CreateResult
Object
Field | Type | Description |
---|---|---|
action | "create" | The type of action performed on this object's input index. |
index | number | Index of input in request body that this action is being performed on. |
success | boolean | Whether the action was successful or not. |
CreateResultSuccess
extends CreateResult
Field | Type | Description |
---|---|---|
success | true | Indicates the import action was successful. |
id | string | Privy DID of the newly created user account. |
CreateResultFailure
extends CreateResult
Field | Type | Description |
---|---|---|
success | false | Indicates the import action failed. |
code | number | Known error code representing failure reason. |
error | string | Human readable error message. |
cause | string | Machine readable error cause (i.e. DID of offending user). |
Error Codes and Causes
Code | Error | Cause Description |
---|---|---|
100 | Unknown error. | N/A |
101 | Account conflict caused by an existing user. Multiple users cannot share the same account. | DID of first existing user that conflicts with input. If the import contains multiple linked accounts, there may be more than one conflict. |
Below is a sample successful response for importing multiple new users into Privy:
json
{
"results": [
{
"action": "create",
"index": 0,
"success": true,
"id": "did:privy:clfn2wysq01ijykc8gyq2j2t1"
},
{
"action": "create",
"index": 1,
"success": false,
"code": 101,
"error": "Account conflict caused by an existing user. Multiple users cannot share the same account.",
"cause": "did:privy:clfmxole300rmykc89nojp3v2"
}
]
}
INFO
User import endpoints have heavier rate limit of 240 users per minute. If you are being rate limited, responses will have status code 429. We suggest you setup exponential back-offs starting at 1 second to seamlessly recover.
INFO
When a user logs in to your app with Google or Apple OAuth, if there is an existing email account associated with the email address used for Google/Apple OAuth, Privy will automatically authenticate the user into the existing email account. This helps prevent account duplication issues where a single user may have multiple accounts unnecessarily.
When importing users to Privy, Privy will not automatically merge Apple, Google, and email users with the same email address if imported separately. This is to support migrations from authentication systems that do not automatically merge Apple, Google, and email accounts on the basis of email address.
If you'd like to import a Google account and email account to have the same Privy DID, you must import both accounts in the same linked_accounts
array. If you import each account separately, they will have different Privy DIDs.
See a list of the different account types and the data they include
Note:
- Each account should be a JSON object including all the necessary fields for that account
type
.- Valid account
type
s areapple_oauth
,'custom_auth'
,'discord_oauth'
,'farcaster'
,'github_oauth'
,'google_oauth'
,'instagram_oauth'
,'linkedin_oauth'
,'spotify_oauth'
,'telegram'
,'tiktok_oauth'
,'twitter_oauth'
,'email'
,'phone'
and'wallet'
.
- Valid account
- If importing a user with a
custom_auth
account, thecustom_auth
account must be the only element of thelinked_accounts
array. It is not permitted to import a user with acustom_auth
account and otherlinked_accounts
. - You must exclude the
verifiedAt
field. - The SDK and REST API have different naming conventions. The SDK uses camelCase and the API uses snake_case.
CustomJwtAccount
Field | Type | Description |
---|---|---|
type | 'custom_auth' | N/A |
API: custom_user_id SDK: customUserId | string | ID of user from custom auth provider. |
DiscordAccount
Field | Type | Description |
---|---|---|
type | 'discord_oauth' | N/A |
subject | string | ID of user from Discord user API response. |
email | string | Email of user from Discord user API response. |
username | string | Username of user from Discord user API response. |
(See Discord docs)
EmailAccount
Field | Type | Description |
---|---|---|
type | 'email' | N/A |
address | string | Email address of user account. |
FarcasterAccount
Field | Type | Description |
---|---|---|
type | 'farcaster' | N/A |
fid | number | FID of the user from Farcaster user API response. |
API: owner_address SDK: ownerAddress | string | Wallet address of the user from Farcaster user API response. Note that this is the Farcaster wallet address, and not the Privy embedded wallet address. |
username | string | (Optional) Username of user from Farcaster user API response. Do not include the '@'. |
API: display_name SDK: displayName | string | (Optional) Display name of user from Farcaster user API response. |
bio | string | (Optional) Bio of user from Farcaster user API response. |
API: profile_picture_url SDK: profilePictureUrl | string | (Optional) Profile picture URL of the user from Farcaster user API response. Must be a valid image URL. |
API: homepage_url SDK: homepageUrl | string | (Optional) Profile URL of the user from Farcaster user API response. |
(See Farcaster docs. Note that the Privy import interface differs slightly from the Farcaster public interface in order to maintain consistency with other Privy LinkedAccount
types.)
GithubAccount
Field | Type | Description |
---|---|---|
type | 'github_oauth' | N/A |
subject | string | ID of user from GitHub user API response. |
email | string | Email of user from GitHub user API response |
name | string | Name of user from GitHub user API response |
username | string | Username of user from GitHub user API response |
(See GitHub docs)
GoogleAccount
Field | Type | Description |
---|---|---|
type | 'google_oauth' | N/A |
subject | string | sub pulled from Google-provided JWT with "openid" scope. |
email | string | email from Google-provided JWT with "email" scope. |
name | string | name from Google-provided JWT with "profile" scope. |
InstagramAccount
Field | Type | Description |
---|---|---|
type | 'instagram_oauth' | N/A |
subject | string | ID of user from Instagram user API response. |
username | string | The name displayed on a user's profile from Instagram's /me API response. |
(See Instagram docs)
LinkedinAccount
Field | Type | Description |
---|---|---|
type | 'linkedin_oauth' | N/A |
subject | string | ID of user from LinkedIn user API response. |
email | string | Email of user from LinkedIn user API response |
name | string | Name of user from LinkedIn user API response. Do not include the '@'. |
(See Linkedin docs)
PhoneAccount
Field | Type | Description |
---|---|---|
type | 'phone' | N/A |
number | string | Phone number of user account (non-international numbers default to US). |
While number
is accepted as input, phoneNumber
is returned in the response.
SmartWalletAccount
Field | Type | Description |
---|---|---|
type | 'smart_wallet' | N/A |
address | string | Checksummed smart wallet address. |
smart_wallet_type | SmartWalletType | One of 'kernel' , 'safe' , 'biconomy' or 'light_account' |
SpotifyAccount
Field | Type | Description |
---|---|---|
type | 'spotify_oauth' | N/A |
subject | string | ID of user from Spotify user API response. |
email | string | Email of user from Spotify user API. |
name | string | The name displayed on a user's profile from Spotify display_name API response. |
(See Spotify docs)
TelegramAccount
Field | Type | Description |
---|---|---|
type | 'telegram' | N/A |
telegram_user_id | string | ID of a user's telegram account. |
first_name | string | The first name displayed on a user's telegram account. |
last_name | string | (Optional) The last name displayed on a user's telegram account. |
username | string | (Optional) The username displayed on a user's telegram account. |
photo_url | string | (Optional) The url of a user's telegram account profile picture. |
(See Telegram docs)
TwitterAccount
Field | Type | Description |
---|---|---|
type | 'twitter_oauth' | N/A |
subject | string | ID of user from Twitter user API response. |
name | string | Name of user from Twitter user API response |
username | string | Username of user from Twitter user API response. Do not include the '@'. |
API: profile_picture_url SDK: profilePictureUrl | string | (Optional) Profile picture URL of the user from Twitter user API response. Must be a valid image URL. |
(See Twitter docs)
WalletAccount
Field | Type | Description |
---|---|---|
type | 'wallet' | N/A |
API: chain_type SDK: chainType | 'ethereum' | Type of chain for the wallet. EVM chains ('ethereum' ) and Solana ('solana' ) are currently supported. |
address | string | Checksummed wallet address. |