Recover assets
Move an asset balance out of a lost or compromised wallet, or return a stray ERC-20, through the governed recovery API.
When a holder loses access to a wallet, or an unrelated token lands in an asset contract by mistake, an institution needs a governed way to move the affected balance without asking the original wallet to sign. DALP exposes three recovery operations on the asset for exactly these cases. Each one is a first-class, role-gated API call that a regulated operator can run under an approved recovery process and reconcile afterward.
These three operations act on the balances of one asset. To provision a replacement wallet and identity for a user across all their holdings, use identity recovery instead.
The diagram shows how the platform routes a recovery instruction. It validates the caller's role and wallet verification, then submits the on-chain call through the durable transaction queue. The recovery takes effect after the transaction confirms, and the indexed balances update after the indexer processes that block.
Choose the recovery operation
Pick the operation that matches the approved recovery decision.
| Decision | Operation | Endpoint | Role |
|---|---|---|---|
| A holder lost a wallet and recovers their own balance to a new wallet | Standard recovery | POST /api/v2/tokens/{tokenAddress}/recoveries | Emergency |
| Recover a holder's balance to a replacement wallet you specify | Forced recovery | POST /api/v2/tokens/{tokenAddress}/forced-recoveries | Custodian, with the CUSTODIAN extension |
| An unrelated ERC-20 was sent to the asset contract and must be returned | ERC-20 recovery | POST /api/v2/tokens/{tokenAddress}/erc20-recoveries | Emergency |
Standard recovery and forced recovery both move the asset's own holder balance out of a lost wallet. They differ in who names the destination. Standard recovery sends the balance to the caller's own wallet, so it fits a holder who recovers their own position. Forced recovery sends the balance to a replacement wallet named in the request, so it fits a custodian who recovers on a holder's behalf.
ERC-20 recovery is a different operation. It moves a foreign token that is sitting in the asset contract address by mistake, not any holder balance of the asset itself.
Prerequisites
Confirm the following before you submit a recovery instruction.
- Platform URL, for example
https://your-platform.example.com - API key for a user with the required role: Emergency for standard and ERC-20 recovery, Custodian for forced recovery
- For forced recovery, the asset must include the CUSTODIAN token extension
- Wallet verification for the signing account, when the platform requires a PIN, OTP, or secret code
- Token contract address for the asset you administer
- The lost wallet address, and for forced recovery the replacement wallet address
- Approval evidence for the recovery decision
Recover a holder's own balance
Send a POST to the recoveries endpoint with the lost wallet address. The
platform moves the asset balance from the lost wallet to the caller's wallet.
curl -X POST https://your-platform.example.com/api/v2/tokens/0xTOKEN/recoveries \
-H "X-Api-Key: sm_dalp_xxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: recover-case-2026-01-15-001" \
-H "Content-Type: application/json" \
-d '{
"lostWallet": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F"
}'The platform validates the caller's Emergency role, wallet verification, and request shape, then queues the transaction and returns an asynchronous response with a transaction identifier and a status URL.
Recover a holder's balance to a replacement wallet
Send a POST to the forced-recoveries endpoint with the lost wallet and the
replacement wallet. Forced recovery requires the Custodian role because the
caller names both the source and the destination.
curl -X POST https://your-platform.example.com/api/v2/tokens/0xTOKEN/forced-recoveries \
-H "X-Api-Key: sm_dalp_xxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: forced-recover-case-2026-01-15-001" \
-H "Content-Type: application/json" \
-d '{
"lostWallet": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
"newWallet": "0x8ba1f109551bD432803012645Ac136ddd64DBA72"
}'The replacement wallet still needs the identity registration or verification that the asset requires of any recipient. Confirm the new wallet is eligible to hold the asset before you submit the request.
Return a stray ERC-20 from the contract
Send a POST to the erc20-recoveries endpoint when an unrelated ERC-20 token
was sent to the asset contract address and needs to be returned. Name the
foreign token, the recipient, and the amount in that token's base units.
curl -X POST https://your-platform.example.com/api/v2/tokens/0xTOKEN/erc20-recoveries \
-H "X-Api-Key: sm_dalp_xxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: erc20-recover-case-2026-01-15-001" \
-H "Content-Type: application/json" \
-d '{
"erc20Address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"recipient": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
"amount": "1000000000000000000"
}'This operation moves the foreign token held by the asset contract. It does not touch any holder balance of the asset itself.
Request bodies
Standard recovery (/recoveries):
| Field | Type | Required | Description |
|---|---|---|---|
lostWallet | string | Yes | Holder address that lost access and holds the balance. |
Forced recovery (/forced-recoveries):
| Field | Type | Required | Description |
|---|---|---|---|
lostWallet | string | Yes | Holder address the balance moves from. |
newWallet | string | Yes | Replacement address the balance moves to. |
ERC-20 recovery (/erc20-recoveries):
| Field | Type | Required | Description |
|---|---|---|---|
erc20Address | string | Yes | Foreign ERC-20 token to recover from the asset contract. |
recipient | string | Yes | Address that receives the recovered tokens. |
amount | string | Yes | Amount in the foreign token's base units. See Asset decimals. |
Every recovery request also accepts an optional walletVerification object when
your platform requires a PIN, OTP, or secret code for the signing account.
What to verify after submission
Treat a recovery the same way you treat any other governed servicing operation on the asset.
- Confirm the affected holder balances or token events through your operating view or API integration after the transaction confirms.
- Record the token address, source address, destination address, amount where it applies, approving operator, request identifier, and transaction hash.
- Keep the recovery approval and identity evidence outside the API request.
- For a forced recovery, confirm the replacement wallet holds the recovered balance and can transact under the asset's compliance rules.
Use idempotency keys
Send an Idempotency-Key header on any recovery your integration may retry
after a timeout. Reuse the same key only when the method, path, and request body
match the original instruction. A retry without a key can queue a duplicate
recovery.
Troubleshooting
| Issue | Check |
|---|---|
401 Unauthorized | Confirm the API key is present, active, and scoped to the platform. |
403 USER_NOT_AUTHORIZED | Confirm the API user has the Emergency role for standard and ERC-20 recovery, or the Custodian role for forced recovery. |
| Forced recovery is rejected | Confirm the asset includes the CUSTODIAN extension and supports custodian operations. |
| Replacement wallet is rejected | Verify the new wallet meets the asset's recipient identity requirement before retrying. |
| Token is paused | Unpause the token before attempting a recovery that moves a holder balance. |
| Nothing recovered from the ERC-20 call | Confirm the foreign token address, the recipient, and that the amount does not exceed what the contract holds. |
Related guides
- Recover a user's identity for the identity-level workflow that provisions a replacement wallet across a user's holdings
- Forced transfer for governed exception moves between holders
- Freeze controls for regulatory and dispute holds
- Token holders and transfers for the recovery, transfer, and freeze API reference
- Track asynchronous transactions for polling queued transaction status
- Per-asset RBAC for Emergency and Custodian role context