Freeze controls
Hold a holder address or lock a specific token amount through the custodian-only address-freeze and partial-freeze API.
Freeze controls let a custodian stop or limit transfers for one holder without moving the holder's tokens. Use them for regulatory holds, sanctions enforcement, dispute holds, and other approved interventions where the asset must stay in place but cannot move. The platform exposes three operations: an address freeze that blocks a holder entirely, a partial freeze that locks a specific amount, and a partial unfreeze that releases a frozen amount.
These are custodian authority operations. They do not ask the holder to sign, and an evaluator reviewing a regulated-asset platform expects them as a first-class, auditable API surface rather than a side effect of a transfer call.
The diagram shows how the platform routes a freeze instruction. It validates the custodian caller and wallet verification, runs the available-balance preflight for a partial freeze, then submits the on-chain call through the durable transaction queue. The hold takes effect after the transaction confirms, and the indexed holder balance updates after the indexer processes that block.
For the web interface workflow, see Freeze and unfreeze balances. For the broader holder and transfer API, see Token holders and transfers.
Prerequisites
Confirm the following before you submit a freeze instruction.
- Platform URL, for example
https://your-platform.example.com - API key for a user with the asset's Custodian role
- 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
- Holder address the hold or release applies to
- For a partial freeze or unfreeze, the amount in the asset's base units
- Approval evidence for the hold or release decision
Choose the freeze operation
Pick the narrowest operation that matches the approved decision.
| Decision | Operation | Endpoint |
|---|---|---|
| Block a holder address from all transfers | Address freeze | PUT /api/v2/tokens/{tokenAddress}/address-freezes |
| Release a blocked holder address | Address freeze | PUT /api/v2/tokens/{tokenAddress}/address-freezes |
| Lock a specific amount of one holder's balance | Partial freeze | POST /api/v2/tokens/{tokenAddress}/partial-freezes |
| Release a previously frozen amount | Partial unfreeze | POST /api/v2/tokens/{tokenAddress}/partial-unfreezes |
An address freeze and its release use the same endpoint with the freeze flag.
A partial freeze and a partial unfreeze are separate endpoints because they move
different amounts in different directions.
Freeze or release a holder address
Send a PUT to the address-freezes endpoint with the holder address and the
freeze flag. Set freeze to true to block the address.
curl -X PUT https://your-platform.example.com/api/v2/tokens/0xTOKEN/address-freezes \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Idempotency-Key: freeze-address-case-2026-01-15-001" \
-H "Content-Type: application/json" \
-d '{
"userAddress": "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
"freeze": true
}'Release the address by sending the same holder with freeze set to false.
curl -X PUT https://your-platform.example.com/api/v2/tokens/0xTOKEN/address-freezes \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Idempotency-Key: clear-address-freeze-case-2026-01-15-001" \
-H "Content-Type: application/json" \
-d '{
"userAddress": "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
"freeze": false
}'The address freeze sets a holder-level flag that blocks the address from sending or receiving the asset. A partial unfreeze does not clear it; use the address freeze in release mode to lift a whole-address hold.
Lock a specific amount
Send a POST to the partial-freezes endpoint with the holder address and the
amount to lock in the asset's base units.
curl -X POST https://your-platform.example.com/api/v2/tokens/0xTOKEN/partial-freezes \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Idempotency-Key: partial-freeze-case-2026-01-15-001" \
-H "Content-Type: application/json" \
-d '{
"userAddress": "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
"amount": "1000000000000000000"
}'When the indexer already has a balance row for the holder, the platform checks
the holder's available balance before it queues the transaction. Available
balance excludes amounts that are already frozen. If the requested amount
exceeds it, the request returns DALP-0334 and no transaction is queued. Reduce
the amount, or wait for the indexer to reflect a recent transfer, then retry.
When the holder row is still indexing, the platform can queue the transaction
and the on-chain call enforces the balance constraint.
Release a frozen amount
Send a POST to the partial-unfreezes endpoint with the holder address and the
amount to release.
curl -X POST https://your-platform.example.com/api/v2/tokens/0xTOKEN/partial-unfreezes \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Idempotency-Key: partial-unfreeze-case-2026-01-15-001" \
-H "Content-Type: application/json" \
-d '{
"userAddress": "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
"amount": "1000000000000000000"
}'The released amount returns to the holder's available balance and can move again through normal transfers, subject to the asset's compliance rules.
Understand queued execution
Every freeze operation submits through the durable transaction queue. The platform validates the caller, runs the partial-freeze preflight, then accepts the work and returns an asynchronous response with a transaction identifier and a status URL.
{
"transactionId": "018f2f2b-7c8a-7b40-9d46-5b5a51b8e3a1",
"status": "QUEUED",
"statusUrl": "/api/v2/transaction-requests/018f2f2b-7c8a-7b40-9d46-5b5a51b8e3a1"
}The hold takes effect after the transaction confirms on-chain. The indexed holder balance and freeze state update after the indexer processes that block, so read the holder endpoint after confirmation rather than immediately after the call returns. See Track asynchronous transactions for polling the status URL.
Each freeze operation targets one holder per request. To hold several addresses, send one request per holder and reconcile each queued transaction separately.
Use idempotency keys
Send an Idempotency-Key header on each freeze, release, partial-freeze, or
partial-unfreeze instruction that 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 hold.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
userAddress | string | Yes | Holder address the hold or release applies to. |
freeze | boolean | Address freeze only | Set to true to block the holder address, or false to release it. Used by the address-freezes endpoint. |
amount | string | Partial operations only | Positive amount in the asset's base units. Used by the partial-freezes and partial-unfreezes endpoints. See Asset decimals. |
walletVerification | object | Platform-dependent | Wallet verification payload when your platform requires a PIN, OTP, or secret code for the signing account. |
What to verify after submission
Treat a freeze the same way you treat other custodian interventions.
- Confirm the holder's freeze state or frozen amount through the holder endpoint after the transaction confirms.
- Record the token address, holder address, amount, approving operator, request identifier, and transaction hash.
- Keep the legal or compliance approval evidence outside the API request.
- For a release, confirm the available balance returned before you allow normal transfers.
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 Custodian role for the asset. |
DALP-0334 | The partial-freeze amount exceeds the holder's available balance. Read the current available balance and resubmit a smaller amount. |
| Asset does not support the control | Confirm the asset supports custodian operations. Freeze controls require the custodian capability on the token. |
| Holder still cannot transfer | Check the address freeze flag, any remaining frozen amount, normal compliance checks, and the asset's pause state. |
Related guides
- Freeze and unfreeze balances for the web interface workflow
- Token holders and transfers for the wider holder, transfer, and recovery API
- Forced transfer for governed exception moves
- Track asynchronous transactions for polling queued transaction status
- Per-asset RBAC for Custodian role context