Appearance
Importing multiple users
In addition to single user import, Privy also allows you to import your users in batches to simplify the migration process. You may import up to 20 users in a single request.
Using @privy-io/server-auth
Use the PrivyClient
's importUsers
method to import a single user into your Privy app.
tsx
const user = await privy.importUsers([
{
linkedAccounts: [{type: 'email', address: '[email protected]'}],
createEmbeddedWallet: true,
},
{
linkedAccounts: [{type: 'email', address: '[email protected]'}],
createEmbeddedWallet: true,
},
{
linkedAccounts: [{type: 'phones', number: '+1 123 456 7890'}],
createEmbeddedWallet: true,
},
]);
As a parameter to the method, pass an array of ImportUserInput
objects. Each object should contain the following fields:
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. |
createEmbeddedWallet | boolean | (Optional) Whether to create an embedded wallet for the imported user. Defaults to false . |
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. You can see the types for this object, and the nested LinkedAccount
objects below.
See the types for `ImportUser` objects
ImportUser
Object
Field | Type | Description |
---|---|---|
linked_accounts | LinkedAccount[] | An array including all of the user's linked accounts. |
create_embedded_wallet | boolean | (Optional) Whether to pregenerate an embedded wallet for the imported user. Defaults to false . |
See the types for LinkedAccount
objects
Note:
- Each account should be a JSON object including all the necessary fields for that account
type
. Valid accounttype
s are'wallet'
,'email'
,'phone'
,'discord_oauth'
,'github_oauth'
,'twitter_oauth'
,'google_oauth'
,'linkedin_oauth'
,'farcaster'
, and'custom_jwt'
. See below for what additional information for each accounttype
. Please exclude theverifiedAt
field. - If importing a user with a
custom_jwt
account, thecustom_jwt
account must be the only element of thelinked_accounts
array. It is not permitted to import a user with acustom_jwt
account and otherlinked_accounts
.
EmailAccount
extends LinkedAccount
Field | Type | Description |
---|---|---|
type | 'email' | N/A |
address | string | Email address of user account. |
PhoneAccount
extends LinkedAccount
Field | Type | Description |
---|---|---|
type | 'email' | N/A |
number | true | Phone number of user account (non-international numbers default to US). |
WalletAccount
extends LinkedAccount
Field | Type | Description |
---|---|---|
type | 'wallet' | N/A |
chain_type | 'ethereum' | Type of chain for the wallet. Only EVM chains ('ethereum' ) are currently supported. |
address | string | Checksummed wallet address. |
GoogleAccount
extends LinkedAccount
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. |
GithubAccount
extends LinkedAccount
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)
DiscordAccount
extends LinkedAccount
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. Include the 4-digit discriminator prefixed by '#'. |
(See Discord docs)
TwitterAccount
extends LinkedAccount
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 '@'. |
(See Twitter docs)
LinkedinAccount
extends LinkedAccount
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)
SpotifyAccount
extends LinkedAccount
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)
CustomJwtAccount
extends LinkedAccount
Field | Type | Description |
---|---|---|
type | 'custom_jwt' | N/A |
custom_id | string | ID of user from Twitter user API response. |
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.
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": "[email protected]"
}
]
},
{
"linked_accounts": [
{
"type": "wallet",
"chain_type": "ethereum",
"address": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045"
}
]
},
{
"linked_accounts": [
{
"type": "phone",
"number": "18888675309"
}
]
},
{
"linked_accounts": [
{
"type": "email",
"address": "[email protected]"
}
]
}
]
}'
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. |
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.
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"
}
]
}