Migrate User Without Wallet (Single)
Creates one user and asks the custody provider for a wallet on the default network of the chain named by chain_id. The user is stored synchronously; the wallet (custody: true) is created asynchronously and appears in List User Wallets once custody answers. Unless kyc_sent is true, the platform then sends its KYC token(s) to the new wallet on every network of the chain. See the overview for the identity, KYC and duplicate rules.
The chain is resolved after the user is stored: if chain_id does not resolve, the request answers 400 but the user already exists without a wallet. Add the wallet with Create User Wallet rather than repeating the migration (it would now be refused as a duplicate).
Required permission: user:create
Request
POST /v2/users/migrate/without-wallet
Headers
| Name | Description |
|---|---|
Authorization | Required. Bearer <access_token> |
Content-Type | Required. application/json |
Body
| Field | Type | Required | Description |
|---|---|---|---|
chain_id | string | Yes | Chain (chains id) to create the custody wallet on. Must have a default network |
email | string | No | Email. Required when external_id is absent; must be a valid email when given |
external_id | string | No | Opaque identifier for KVKK-anonymized migration. Required when email is absent |
name | string | No | First name; not stored when empty |
surname | string | No | Last name; not stored when empty |
kyc_sent | boolean | No | Default false. true means KYC was already done: nothing is sent and the new wallet is recorded as KYC-verified on the chain's default network |
Example
curl --request POST \
--url '{{baseUrl}}/v2/users/migrate/without-wallet' \
--header 'Authorization: Bearer <access_token>' \
--header 'Content-Type: application/json' \
--data '{
"email": "auto@example.com",
"name": "Auto",
"surname": "Wallet",
"chain_id": "6740e0a10000000000000101",
"kyc_sent": false
}'
KVKK mode (identifier only):
curl --request POST \
--url '{{baseUrl}}/v2/users/migrate/without-wallet' \
--header 'Authorization: Bearer <access_token>' \
--header 'Content-Type: application/json' \
--data '{
"external_id": "EXT-9001",
"chain_id": "6740e0a10000000000000101",
"kyc_sent": true
}'
Response
Status Code: 201 Created
{
"id": "6913872755654191dede37da",
"external_id": "EXT-9001",
"name": "",
"surname": "",
"email": "",
"identity_number": "",
"status": 0,
"created_at": "2026-08-21T09:14:02.511Z",
"kyc": null
}
The created user, in the shape of Get User by ID. The wallet does not exist yet at this point; poll List User Wallets.
Errors
| Status | Code | Description |
|---|---|---|
| 400 | 10015 | Validation failed (chain_id missing, malformed email) — see details |
| 400 | 10015 | Row skipped; message is the reason: missing_email_and_external_id, duplicate_email or duplicate_external_id |
| 400 | 10015 | chain not found / chain has no default network configured. The user has already been created |
| 400 | 10016 | chain_id is not a valid id. The user has already been created |
For imports where one bad row must not stop the rest, use Bulk or CSV. See Errors for the error format and common codes.