Forced transfer
Administratively move assets between wallets for compliance or recovery via API.
A forced transfer moves assets between accounts without the holder's consent or signature. This replicates the authority that traditional custodians and transfer agents have to move securities under specific legal circumstances.
For the web interface approach, see the user guide.
Prerequisites
- Platform URL (e.g.,
https://your-platform.example.com) - API key from a user with Custodian role on this asset (see Getting Started for API key setup)
- Wallet verification method enabled on your account (e.g., pincode or 2FA)
- Source address must hold sufficient balance
Compliance bypass
Forced transfers bypass normal wallet authorization. Only use for legitimate compliance, legal, or recovery situations. All forced transfers are permanently recorded on-chain.
Executing a forced transfer
Prepare API request
Construct the API request with source, destination, and amount:
curl -X POST "https://your-platform.example.com/api/token/0x9459D52E60edBD3178f00F9055f6C117a21b4220/transfer/forced" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "0x8e5F72f6E5b3B4D1234567890AbCdEf1234567890",
"recipients": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"amounts": ["100000000000000000000", 18],
"walletVerification": {
"secretVerificationCode": "123456",
"verificationType": "PINCODE"
}
}'Asset address in path
The asset contract address is part of the URL path: /api/token/{tokenAddress} /transfer/forced
Amount formatting
Asset amounts depend on the asset's decimal configuration. See Asset Decimals for formatting guidance.
Execute forced transfer
When you execute the request, the platform:
- Validates your permissions - Confirms you have Custodian role on this asset
- Verifies your wallet - Uses your pincode/2FA to authorize the blockchain transaction
- Checks balances - Ensures source address has sufficient balance
- Executes the transfer - Moves assets from source to destination
Handle response
A successful response returns the updated asset data (showing key fields):
{
"id": "0x9459D52E60edBD3178f00F9055f6C117a21b4220",
"type": "equity",
"createdAt": "2025-01-15T10:30:00.000Z",
"name": "ACME Holdings Common Stock",
"symbol": "ACME",
"decimals": 18,
"basePrice": "[\"10000\",2]",
"basePriceCurrencyCode": "USD",
"totalSupply": "[\"1000000000000000000000\",18]",
"pausable": {
"paused": false
}
}The response includes the full asset object with additional fields like identity, accessControl, complianceModuleConfigs, userPermissions, and stats.
Document the transfer
Maintain off-chain documentation including:
- Legal authorization or compliance justification
- Approval from appropriate authority
- Date and time of authorization
- Affected parties notification
Batch forced transfers
Move assets from multiple sources to multiple destinations in one transaction:
Prepare batch request
Construct the request with arrays of sources, destinations, and amounts:
curl -X POST "https://your-platform.example.com/api/token/0x9459D52E60edBD3178f00F9055f6C117a21b4220/transfer/forced" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": [
"0x8e5F72f6E5b3B4D1234567890AbCdEf1234567890",
"0x1234567890AbCdEf1234567890AbCdEf12345678"
],
"recipients": [
"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"0xabcdef1234567890abcdef1234567890abcdef12"
],
"amounts": [
["100000000000000000000", 18],
["50000000000000000000", 18]
],
"walletVerification": {
"secretVerificationCode": "123456",
"verificationType": "PINCODE"
}
}'Array lengths must match
The from, recipients, and amounts arrays must all have the same length.
Each transfer is: from[i] → recipients[i] for amounts[i].
Execute batch transfer
The platform validates all transfers before executing. If any transfer fails validation, the entire batch is rejected.
Batch limits:
- Maximum 100 transfers per API call
- For larger operations, split into multiple calls
Request parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
from | string or array | Yes | Source wallet address(es) (assets seized from) |
recipients | string or array | Yes | Destination wallet address(es) (assets sent to) |
amounts | string or array | Yes | Amount(s) as dnum tuple [scaled_value, decimals]. See Asset Decimals |
walletVerification | object | Yes | Your wallet verification |
walletVerification.secretVerificationCode | string | Yes | Your 6-digit PINCODE or TOTP code |
walletVerification.verificationType | string | Yes | "PINCODE", "OTP", or "SECRET_CODES" |
Troubleshooting
| Issue | Solution |
|---|---|
401 Unauthorized | API key is invalid, expired, or disabled |
403 USER_NOT_AUTHORIZED | Ensure your account has custodian role on this asset |
Asset is paused | Unpause the asset first |
Source has insufficient balance | Check balance of from address |
Recipient not compliant | Recipient must meet compliance requirements |
Array length mismatch | from, recipients, and amounts arrays must have same length |
Related guides
- Pause/Unpause Assets - Enable/disable transfers
- Mint Assets - Issue assets to investors