Migrate Users Without Wallets (Bulk)
Migrates up to 500 users in one request; a custody wallet is created asynchronously for each created user. Each row is processed like the single endpoint and reported on its own: the request answers 200 even when some rows are skipped or failed. Every row is validated first; one invalid row (for example a missing chain_id) rejects the whole request.
A row whose chain_id does not resolve is reported as failed without a user_id, but its user has already been stored (without a wallet). Add the wallet with Create User Wallet rather than re-running the row.
Required permission: user:create
Request
POST /v2/users/migrate/without-wallet/bulk
Headers
| Name | Description |
|---|---|
Authorization | Required. Bearer <access_token> |
Content-Type | Required. application/json |
Body
| Field | Type | Required | Description |
|---|---|---|---|
users | array | Yes | 1–500 rows, each with the fields of the single endpoint (chain_id required on every row) |
Example
curl --request POST \
--url '{{baseUrl}}/v2/users/migrate/without-wallet/bulk' \
--header 'Authorization: Bearer <access_token>' \
--header 'Content-Type: application/json' \
--data '{
"users": [
{ "email": "classic@example.com", "name": "Classic", "surname": "User", "chain_id": "6740e0a10000000000000101" },
{ "external_id": "EXT-A", "chain_id": "6740e0a10000000000000101", "kyc_sent": true },
{ "external_id": "EXT-B", "email": "hybrid@example.com", "chain_id": "6740e0a10000000000000101" }
]
}'
Response
{
"total": 3,
"success": 3,
"skipped": 0,
"failed": 0,
"results": [
{ "email": "classic@example.com", "user_id": "6913872755654191dede37da", "status": "created" },
{ "external_id": "EXT-A", "user_id": "6913872755654191dede37db", "status": "created" },
{ "external_id": "EXT-B", "email": "hybrid@example.com", "user_id": "6913872755654191dede37dc", "status": "created" }
]
}
Response Fields
Same fields as the with-wallet bulk response. On skipped rows reason is missing_email_and_external_id, duplicate_email or duplicate_external_id (duplicate_wallet and invalid_chain do not occur in this flow); on failed rows it is free text.
Errors
| Status | Code | Description |
|---|---|---|
| 400 | 10015 | Validation failed (empty users, more than 500 rows, a row without chain_id, a malformed email) — see details |
See Errors for the error format and common codes.